diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index 1b119fad8d..ac6496edaa 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -643,6 +643,7 @@ 8484E9D8103C95A6008B7C6C /* juce_posix_SharedCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 8484E9D6103C95A6008B7C6C /* juce_posix_SharedCode.h */; }; 8484E9D9103C95A6008B7C6C /* juce_posix_NamedPipe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8484E9D7103C95A6008B7C6C /* juce_posix_NamedPipe.cpp */; }; 84A63C02107DF286000326FD /* juce_mac_ObjCSuffix.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A63C01107DF286000326FD /* juce_mac_ObjCSuffix.h */; }; + 84AB6F6E10EF948B00117E64 /* juce_HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */; }; 84AB91FB10A078190048FC39 /* juce_CodeDocument.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84AB91F510A078190048FC39 /* juce_CodeDocument.cpp */; }; 84AB91FC10A078190048FC39 /* juce_CodeDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 84AB91F610A078190048FC39 /* juce_CodeDocument.h */; }; 84AB91FD10A078190048FC39 /* juce_CodeEditorComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84AB91F710A078190048FC39 /* juce_CodeEditorComponent.cpp */; }; @@ -653,6 +654,7 @@ 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 */; }; 84D0F00C109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */; }; + 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */; }; 84F1E6E710403605006A1807 /* juce_Application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F1E6DC10403605006A1807 /* juce_Application.cpp */; }; 84F1E6E810403605006A1807 /* juce_Application.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F1E6DD10403605006A1807 /* juce_Application.h */; }; 84F1E6E910403605006A1807 /* juce_ApplicationCommandID.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F1E6DE10403605006A1807 /* juce_ApplicationCommandID.h */; }; @@ -1260,6 +1262,7 @@ 84AB91FA10A078190048FC39 /* juce_CPlusPlusCodeTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_CPlusPlusCodeTokeniser.h; path = components/code_editor/juce_CPlusPlusCodeTokeniser.h; sourceTree = ""; }; 84AB927110A082E30048FC39 /* juce_CodeTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_CodeTokeniser.h; path = components/code_editor/juce_CodeTokeniser.h; sourceTree = ""; }; 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = juce_mac_CoreGraphicsContext.mm; sourceTree = ""; }; + 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_HeapBlock.h; sourceTree = ""; }; 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; }; 84F1E6DD10403605006A1807 /* juce_Application.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_Application.h; path = ../../src/application/juce_Application.h; sourceTree = SOURCE_ROOT; }; 84F1E6DE10403605006A1807 /* juce_ApplicationCommandID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_ApplicationCommandID.h; path = ../../src/application/juce_ApplicationCommandID.h; sourceTree = SOURCE_ROOT; }; @@ -2162,6 +2165,7 @@ 84F1E8D510403671006A1807 /* juce_MemoryBlock.cpp */, 84F1E8D610403671006A1807 /* juce_MemoryBlock.h */, 84F1E8D710403671006A1807 /* juce_OwnedArray.h */, + 84DEDD9E10EE496500909D01 /* juce_HeapBlock.h */, 84F1E8D810403671006A1807 /* juce_PropertySet.cpp */, 84F1E8D910403671006A1807 /* juce_PropertySet.h */, 84F1E8DA10403671006A1807 /* juce_ReferenceCountedArray.h */, @@ -3206,6 +3210,7 @@ 844BB95D10C5579B00DF5536 /* juce_FillType.h in Headers */, 844BB95F10C557A800DF5536 /* juce_Config.h in Headers */, 84B2053E10D535EC008B4A79 /* juce_ValueTree.h in Headers */, + 84AB6F6E10EF948B00117E64 /* juce_HeapBlock.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3530,6 +3535,7 @@ 84AB927210A082E30048FC39 /* juce_CodeTokeniser.h in Headers */, 84F29AA010C2EFA5005014DF /* juce_FillType.h in Headers */, 843D4A3C10D3C54500624BA6 /* juce_ValueTree.h in Headers */, + 84DEDD9F10EE496500909D01 /* juce_HeapBlock.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/build/win32/vc8/JUCE.vcproj b/build/win32/vc8/JUCE.vcproj index 33145ff9b7..50fc89a61d 100644 --- a/build/win32/vc8/JUCE.vcproj +++ b/build/win32/vc8/JUCE.vcproj @@ -1085,6 +1085,10 @@ RelativePath="..\..\..\src\containers\juce_ElementComparator.h" > + + diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index 6358d47ed3..a4340a8cc2 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -127,7 +127,6 @@ public: #endif juceFilter (0), bufferSpace (2, 16), - channels (0), prepared (false) { if (activePlugins.size() + activeUIs.size() == 0) @@ -162,9 +161,6 @@ public: delete juceFilter; juceFilter = 0; - juce_free (channels); - channels = 0; - jassert (activePlugins.contains (this)); activePlugins.removeValue (this); @@ -659,9 +655,8 @@ public: midiEvents.clear(); incomingEvents.clear(); - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(), - juceFilter->getNumOutputChannels()) + 4); + channels.calloc (jmax (juceFilter->getNumInputChannels(), + juceFilter->getNumOutputChannels()) + 4); prepared = true; } @@ -940,7 +935,7 @@ protected: private: AudioProcessor* juceFilter; AudioSampleBuffer bufferSpace; - float** channels; + HeapBlock channels; MidiBuffer midiEvents, incomingEvents; bool prepared; SMPTETime lastSMPTETime; diff --git a/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp b/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp index 931c6a09cd..0f161faa28 100644 --- a/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp +++ b/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp @@ -159,7 +159,6 @@ public: JucePlugInProcess() : midiBufferNode (0), midiTransport (0), - channels (0), prepared (false), sampleRate (44100.0) { @@ -183,7 +182,6 @@ public: juceFilter->releaseResources(); delete juceFilter; - juce_free (channels); if (--numInstances == 0) shutdownJuce_GUI(); @@ -509,9 +507,8 @@ protected: sampleRate = gProcessGroup->GetSampleRate(); jassert (sampleRate > 0); - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(), - juceFilter->getNumOutputChannels())); + channels.calloc (jmax (juceFilter->getNumInputChannels(), + juceFilter->getNumOutputChannels())); juceFilter->setPlayConfigDetails (fNumInputs, fNumOutputs, sampleRate, mRTGlobals->mHWBufferSizeInSamples); @@ -807,7 +804,7 @@ private: DirectMidiPacket midiBuffer [midiBufferSize]; JUCE_NAMESPACE::MemoryBlock tempFilterData; - float** channels; + HeapBlock channels; bool prepared; double sampleRate; diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index c1ab2a687a..c3d966296f 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -383,7 +383,6 @@ public: hasShutdown = false; firstProcessCallback = true; shouldDeleteEditor = false; - channels = 0; speakerIn = kSpeakerArrEmpty; speakerOut = kSpeakerArrEmpty; speakerInChans = 0; @@ -439,8 +438,7 @@ public: jassert (editorComp == 0); - juce_free (channels); - channels = 0; + channels.free(); deleteTempChannels(); jassert (activePlugins.contains (this)); @@ -766,8 +764,7 @@ public: return; isProcessing = true; - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * (numInChans + numOutChans)); + channels.calloc (numInChans + numOutChans); double rate = getSampleRate(); jassert (rate > 0); @@ -813,8 +810,7 @@ public: outgoingEvents.freeEvents(); isProcessing = false; - juce_free (channels); - channels = 0; + channels.free(); deleteTempChannels(); } @@ -1398,15 +1394,14 @@ private: VstSpeakerArrangementType speakerIn, speakerOut; int speakerInChans, speakerOutChans; int numInChans, numOutChans; - float** channels; + HeapBlock channels; VoidArray tempChannels; // see note in processReplacing() bool hasCreatedTempChannels; bool shouldDeleteEditor; void deleteTempChannels() { - int i; - for (i = tempChannels.size(); --i >= 0;) + for (int i = tempChannels.size(); --i >= 0;) juce_free (tempChannels.getUnchecked(i)); tempChannels.clear(); diff --git a/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp b/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp index 656b87202c..c27303e7d3 100644 --- a/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp +++ b/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp @@ -124,7 +124,9 @@ public: } else { - var* args = (var*) juce_calloc (sizeof (var) * numArgs); + HeapBlock args; + args.calloc (numArgs); + for (int j = 0; j < numArgs; ++j) args[(numArgs - 1) - j] = variantTojuceVar (pDispParams->rgvarg[j]); @@ -132,8 +134,6 @@ public: for (int j = 0; j < numArgs; ++j) args[j] = var(); - - juce_free (args); } if (pVarResult != 0) @@ -329,7 +329,8 @@ public: DISPID id = 0; if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK) { - VARIANT* params = (VARIANT*) juce_calloc (sizeof (VARIANT) * (numParameters + 1)); + HeapBlock params; + params.calloc (numParameters + 1); for (int i = 0; i < numParameters; ++i) juceVarToVariant (parameters[(numParameters - 1) - i], params[i]); @@ -352,8 +353,6 @@ public: returnValue = variantTojuceVar (result); VariantClear (&result); } - - juce_free (params); } return returnValue; @@ -558,7 +557,8 @@ static const String getExeVersion (const String& exeFileName, const String& fiel if (size > 0) { - void* const exeInfo = juce_calloc (size); + HeapBlock exeInfo; + exeInfo.calloc (size); if (GetFileVersionInfo (exeFileName, 0, size, exeInfo)) { @@ -577,8 +577,6 @@ static const String getExeVersion (const String& exeFileName, const String& fiel resultString = String (result, resultLen); } - - juce_free (exeInfo); } return resultString; diff --git a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp index 17780a4955..8453e7ae53 100644 --- a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp +++ b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp @@ -621,7 +621,7 @@ public: if (numParameters > 0) { - NPVariant* const params = (NPVariant*) juce_malloc (sizeof (NPVariant) * numParameters); + HeapBlock params (numParameters); int i; for (i = 0; i < numParameters; ++i) @@ -636,8 +636,6 @@ public: for (i = 0; i < numParameters; ++i) browser.releasevariantvalue (¶ms[i]); - - juce_free (params); } else { @@ -688,7 +686,9 @@ private: if (o == 0 || ! o->hasMethod (methodName)) return false; - var* params = (var*) juce_calloc (sizeof (var) * argCount); + HeapBlock params; + params.calloc (argCount); + for (uint32_t i = 0; i < argCount; ++i) params[i] = createValueFromNPVariant (npp, args[i]); @@ -697,8 +697,6 @@ private: for (int i = argCount; --i >= 0;) params[i] = var(); - juce_free (params); - if (out != 0) createNPVariantFromValue (npp, *out, result); diff --git a/extras/juce demo/build/win32_vc8/jucedemo.vcproj b/extras/juce demo/build/win32_vc8/jucedemo.vcproj index a36493bcaa..c32dedd3b0 100644 --- a/extras/juce demo/build/win32_vc8/jucedemo.vcproj +++ b/extras/juce demo/build/win32_vc8/jucedemo.vcproj @@ -46,12 +46,13 @@ /> > 5) + 1); negative = other.negative; - const int memSize = sizeof (unsigned int) * (numValues + 1); - values = (unsigned int*)juce_malloc (memSize); - memcpy (values, other.values, memSize); + values.malloc (numValues + 1); + memcpy (values, other.values, sizeof (unsigned int) * (numValues + 1)); } return *this; @@ -2336,9 +2331,8 @@ void BitArray::clear() throw() { if (numValues > 16) { - juce_free (values); numValues = 4; - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); } else { @@ -2986,7 +2980,7 @@ void BitArray::ensureSize (const int numVals) throw() { int oldSize = numValues; numValues = ((numVals + 2) * 3) / 2; - values = (unsigned int*) juce_realloc (values, sizeof (unsigned int) * numValues + 4); + values.realloc (numValues + 1); while (oldSize < numValues) values [oldSize++] = 0; @@ -3120,8 +3114,7 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE MemoryBlock::MemoryBlock() throw() - : data (0), - size (0) + : size (0) { } @@ -3131,35 +3124,28 @@ MemoryBlock::MemoryBlock (const int initialSize, if (initialSize > 0) { size = initialSize; - - if (initialiseToZero) - data = (char*) juce_calloc (initialSize); - else - data = (char*) juce_malloc (initialSize); + data.allocate (initialSize, initialiseToZero); } else { - data = 0; size = 0; } } MemoryBlock::MemoryBlock (const MemoryBlock& other) throw() - : data (0), - size (other.size) + : size (other.size) { if (size > 0) { jassert (other.data != 0); - data = (char*) juce_malloc (size); + data.malloc (size); memcpy (data, other.data, size); } } MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const int sizeInBytes) throw() - : data (0), - size (jmax (0, sizeInBytes)) + : size (jmax (0, sizeInBytes)) { jassert (sizeInBytes >= 0); @@ -3167,7 +3153,7 @@ MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, { jassert (dataToInitialiseFrom != 0); // non-zero size, but a zero pointer passed-in? - data = (char*) juce_malloc (size); + data.malloc (size); if (dataToInitialiseFrom != 0) memcpy (data, dataToInitialiseFrom, size); @@ -3178,8 +3164,6 @@ MemoryBlock::~MemoryBlock() throw() { jassert (size >= 0); // should never happen jassert (size == 0 || data != 0); // non-zero size but no data allocated? - - juce_free (data); } const MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw() @@ -3212,25 +3196,21 @@ void MemoryBlock::setSize (const int newSize, { if (newSize <= 0) { - juce_free (data); - data = 0; + data.free(); size = 0; } else { if (data != 0) { - data = (char*) juce_realloc (data, newSize); + data.realloc (newSize); if (initialiseToZero && (newSize > size)) zeromem (data + size, newSize - size); } else { - if (initialiseToZero) - data = (char*) juce_calloc (newSize); - else - data = (char*) juce_malloc (newSize); + data.allocate (newSize, initialiseToZero); } size = newSize; @@ -3327,7 +3307,7 @@ void MemoryBlock::removeSection (int startByte, int numBytesToRemove) throw() const String MemoryBlock::toString() const throw() { - return String (data, size); + return String ((const char*) data, size); } int MemoryBlock::getBitRange (const int bitRangeStart, int numBits) const throw() @@ -3987,10 +3967,9 @@ void var::writeToStream (OutputStream& output) const throw() const int len = value.stringValue->copyToUTF8 (0); output.writeCompressedInt (len + 1); output.writeByte (5); - uint8* const temp = (uint8*) juce_malloc (len); + HeapBlock temp (len); value.stringValue->copyToUTF8 (temp); output.write (temp, len); - juce_free (temp); break; } case objectType: output.writeCompressedInt (0); jassertfalse; break; // Can't write an object to a stream! @@ -4461,7 +4440,7 @@ BlowFish::BlowFish (const uint8* keyData, int keyBytes) int i, j; for (i = 4; --i >= 0;) { - s[i] = (uint32*) juce_malloc (256 * sizeof (uint32)); + s[i].malloc (256); memcpy (s[i], initialSValues + i * 256, 256 * sizeof (uint32)); } @@ -4507,7 +4486,7 @@ BlowFish::BlowFish (const uint8* keyData, int keyBytes) BlowFish::BlowFish (const BlowFish& other) { for (int i = 4; --i >= 0;) - s[i] = (uint32*) juce_malloc (256 * sizeof (uint32)); + s[i].malloc (256); operator= (other); } @@ -4524,8 +4503,6 @@ const BlowFish& BlowFish::operator= (const BlowFish& other) BlowFish::~BlowFish() { - for (int i = 4; --i >= 0;) - juce_free (s[i]); } uint32 BlowFish::F (uint32 x) const @@ -5697,18 +5674,16 @@ void OutputStream::writeDoubleBigEndian (double value) void OutputStream::writeString (const String& text) { const int numBytes = text.copyToUTF8 (0); - uint8* const temp = (uint8*) juce_malloc (numBytes); + HeapBlock temp (numBytes); text.copyToUTF8 (temp); write (temp, numBytes); // (numBytes includes the terminating null). - - juce_free (temp); } void OutputStream::printf (const char* pf, ...) { unsigned int bufSize = 256; - char* buf = (char*) juce_malloc (bufSize); + HeapBlock buf (bufSize); for (;;) { @@ -5729,12 +5704,9 @@ void OutputStream::printf (const char* pf, ...) break; } - juce_free (buf); bufSize += 256; - buf = (char*) juce_malloc (bufSize); + buf.malloc (bufSize); } - - juce_free (buf); } OutputStream& OutputStream::operator<< (const int number) @@ -6814,15 +6786,25 @@ bool File::hasFileExtension (const String& possibleSuffix) const throw() if (possibleSuffix.isEmpty()) return fullPath.lastIndexOfChar (T('.')) <= fullPath.lastIndexOfChar (separator); - if (fullPath.endsWithIgnoreCase (possibleSuffix)) + const int semicolon = possibleSuffix.indexOfChar (0, T(';')); + + if (semicolon >= 0) { - if (possibleSuffix.startsWithChar (T('.'))) - return true; + return hasFileExtension (possibleSuffix.substring (0, semicolon).trimEnd()) + || hasFileExtension (possibleSuffix.substring (semicolon + 1).trimStart()); + } + else + { + if (fullPath.endsWithIgnoreCase (possibleSuffix)) + { + if (possibleSuffix.startsWithChar (T('.'))) + return true; - const int dotPos = fullPath.length() - possibleSuffix.length() - 1; + const int dotPos = fullPath.length() - possibleSuffix.length() - 1; - if (dotPos >= 0) - return fullPath [dotPos] == T('.'); + if (dotPos >= 0) + return fullPath [dotPos] == T('.'); + } } return false; @@ -7199,7 +7181,7 @@ FileOutputStream::FileOutputStream (const File& f, } } - buffer = (char*) juce_malloc (jmax (bufferSize_, 16)); + buffer.malloc (jmax (bufferSize_, 16)); } FileOutputStream::~FileOutputStream() @@ -7207,7 +7189,6 @@ FileOutputStream::~FileOutputStream() flush(); juce_fileClose (fileHandle); - juce_free (buffer); } int64 FileOutputStream::getPosition() @@ -8538,6 +8519,8 @@ const URL URL::withFileToUpload (const String& parameterName, const File& fileToUpload, const String& mimeType) const { + jassert (mimeType.isNotEmpty()); // You need to supply a mime type! + URL u (*this); u.filesToUpload.set (parameterName, fileToUpload.getFullPathName()); u.mimeTypes.set (parameterName, mimeType); @@ -8569,7 +8552,7 @@ const StringPairArray& URL::getMimeTypesOfUploadFiles() const throw() const String URL::removeEscapeChars (const String& s) { const int len = s.length(); - uint8* const resultUTF8 = (uint8*) juce_calloc (len * 4); + HeapBlock resultUTF8 (len * 4); uint8* r = resultUTF8; for (int i = 0; i < len; ++i) @@ -8591,9 +8574,7 @@ const String URL::removeEscapeChars (const String& s) *r++ = c; } - const String stringResult (String::fromUTF8 (resultUTF8)); - juce_free (resultUTF8); - return stringResult; + return String::fromUTF8 (resultUTF8); } const String URL::addEscapeChars (const String& s, const bool isParameter) @@ -8664,15 +8645,13 @@ BufferedInputStream::BufferedInputStream (InputStream* const source_, bufferSize = jmin (jmax (32, sourceSize), bufferSize); bufferStart = position; - buffer = (char*) juce_malloc (bufferSize); + buffer.malloc (bufferSize); } BufferedInputStream::~BufferedInputStream() throw() { if (deleteSourceWhenDestroyed) delete source; - - juce_free (buffer); } int64 BufferedInputStream::getTotalLength() @@ -8710,7 +8689,7 @@ void BufferedInputStream::ensureBuffered() && position >= bufferStart) { const int bytesToKeep = (int) (lastReadPos - position); - memmove (buffer, buffer + position - bufferStart, bytesToKeep); + memmove (buffer, buffer + (int) (position - bufferStart), bytesToKeep); bufferStart = position; @@ -8738,7 +8717,7 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) if (position >= bufferStart && position + maxBytesToRead <= lastReadPos) { - memcpy (destBuffer, buffer + (position - bufferStart), maxBytesToRead); + memcpy (destBuffer, buffer + (int) (position - bufferStart), maxBytesToRead); position += maxBytesToRead; return maxBytesToRead; @@ -8756,7 +8735,7 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) if (bytesAvailable > 0) { - memcpy (destBuffer, buffer + (position - bufferStart), bytesAvailable); + memcpy (destBuffer, buffer + (int) (position - bufferStart), bytesAvailable); maxBytesToRead -= bytesAvailable; bytesRead += bytesAvailable; position += bytesAvailable; @@ -8784,7 +8763,7 @@ const String BufferedInputStream::readString() { const int maxChars = (int) (lastReadPos - position); - const char* const src = buffer + (position - bufferStart); + const char* const src = buffer + (int) (position - bufferStart); for (int i = 0; i < maxChars; ++i) { @@ -12837,13 +12816,8 @@ bool StringArray::operator== (const StringArray& other) const throw() return false; for (int i = size(); --i >= 0;) - { - if (*(String*) other.strings.getUnchecked(i) - != *(String*) strings.getUnchecked(i)) - { + if (*other.strings.getUnchecked(i) != *strings.getUnchecked(i)) return false; - } - } return true; } @@ -12855,19 +12829,13 @@ bool StringArray::operator!= (const StringArray& other) const throw() void StringArray::clear() throw() { - for (int i = size(); --i >= 0;) - { - String* const s = (String*) strings.getUnchecked(i); - delete s; - } - strings.clear(); } const String& StringArray::operator[] (const int index) const throw() { if (((unsigned int) index) < (unsigned int) strings.size()) - return *(const String*) (strings.getUnchecked (index)); + return *strings.getUnchecked (index); return String::empty; } @@ -12904,22 +12872,18 @@ void StringArray::addArray (const StringArray& otherArray, numElementsToAdd = otherArray.size() - startIndex; while (--numElementsToAdd >= 0) - strings.add (new String (*(const String*) otherArray.strings.getUnchecked (startIndex++))); + strings.add (new String (*otherArray.strings.getUnchecked (startIndex++))); } void StringArray::set (const int index, const String& newString) throw() { - String* const s = (String*) strings [index]; + String* const s = strings [index]; if (s != 0) - { *s = newString; - } else if (index >= 0) - { add (newString); - } } bool StringArray::contains (const String& stringToLookFor, @@ -12928,13 +12892,13 @@ bool StringArray::contains (const String& stringToLookFor, if (ignoreCase) { for (int i = size(); --i >= 0;) - if (stringToLookFor.equalsIgnoreCase (*(const String*)(strings.getUnchecked(i)))) + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToLookFor)) return true; } else { for (int i = size(); --i >= 0;) - if (stringToLookFor == *(const String*)(strings.getUnchecked(i))) + if (stringToLookFor == *strings.getUnchecked(i)) return true; } @@ -12954,7 +12918,7 @@ int StringArray::indexOf (const String& stringToLookFor, { while (i < numElements) { - if (stringToLookFor.equalsIgnoreCase (*(const String*) strings.getUnchecked (i))) + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToLookFor)) return i; ++i; @@ -12964,7 +12928,7 @@ int StringArray::indexOf (const String& stringToLookFor, { while (i < numElements) { - if (stringToLookFor == *(const String*) strings.getUnchecked (i)) + if (stringToLookFor == *strings.getUnchecked (i)) return i; ++i; @@ -12976,13 +12940,7 @@ int StringArray::indexOf (const String& stringToLookFor, void StringArray::remove (const int index) throw() { - String* const s = (String*) strings [index]; - - if (s != 0) - { - strings.remove (index); - delete s; - } + strings.remove (index); } void StringArray::removeString (const String& stringToRemove, @@ -12991,14 +12949,14 @@ void StringArray::removeString (const String& stringToRemove, if (ignoreCase) { for (int i = size(); --i >= 0;) - if (stringToRemove.equalsIgnoreCase (*(const String*) strings.getUnchecked (i))) - remove (i); + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToRemove)) + strings.remove (i); } else { for (int i = size(); --i >= 0;) - if (stringToRemove == *(const String*) strings.getUnchecked (i)) - remove (i); + if (stringToRemove == *strings.getUnchecked (i)) + strings.remove (i); } } @@ -13007,14 +12965,14 @@ void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) throw( if (removeWhitespaceStrings) { for (int i = size(); --i >= 0;) - if (! ((const String*) strings.getUnchecked(i))->containsNonWhitespaceChars()) - remove (i); + if (! strings.getUnchecked(i)->containsNonWhitespaceChars()) + strings.remove (i); } else { for (int i = size(); --i >= 0;) - if (((const String*) strings.getUnchecked(i))->isEmpty()) - remove (i); + if (strings.getUnchecked(i)->isEmpty()) + strings.remove (i); } } @@ -13022,7 +12980,7 @@ void StringArray::trim() throw() { for (int i = size(); --i >= 0;) { - String& s = *(String*) strings.getUnchecked(i); + String& s = *strings.getUnchecked(i); s = s.trim(); } } @@ -13078,13 +13036,13 @@ const String StringArray::joinIntoString (const String& separator, return String::empty; if (start == last - 1) - return *(const String*) strings.getUnchecked (start); + return *strings.getUnchecked (start); const int separatorLen = separator.length(); int charsNeeded = separatorLen * (last - start - 1); for (int i = start; i < last; ++i) - charsNeeded += ((const String*) strings.getUnchecked(i))->length(); + charsNeeded += strings.getUnchecked(i)->length(); String result; result.preallocateStorage (charsNeeded); @@ -13093,7 +13051,7 @@ const String StringArray::joinIntoString (const String& separator, while (start < last) { - const String& s = *(const String*) strings.getUnchecked (start); + const String& s = *strings.getUnchecked (start); const int len = s.length(); if (len > 0) @@ -13258,7 +13216,7 @@ void StringArray::removeDuplicates (const bool ignoreCase) throw() { for (int i = 0; i < size() - 1; ++i) { - const String& s = *(String*) strings.getUnchecked(i); + const String& s = *strings.getUnchecked(i); int nextIndex = i + 1; @@ -13269,7 +13227,7 @@ void StringArray::removeDuplicates (const bool ignoreCase) throw() if (nextIndex < 0) break; - remove (nextIndex); + strings.remove (nextIndex); } } } @@ -13281,7 +13239,7 @@ void StringArray::appendNumbersToDuplicates (const bool ignoreCase, { for (int i = 0; i < size() - 1; ++i) { - String& s = *(String*) strings.getUnchecked(i); + String& s = *strings.getUnchecked(i); int nextIndex = indexOf (s, ignoreCase, i + 1); @@ -15355,20 +15313,15 @@ XmlElement* XmlElement::findParentElementOf (const XmlElement* const elementToLo return 0; } -XmlElement** XmlElement::getChildElementsAsArray (const int num) const throw() +void XmlElement::getChildElementsAsArray (XmlElement** elems) const throw() { - XmlElement** const elems = new XmlElement* [num]; - XmlElement* e = firstChildElement; - int i = 0; while (e != 0) { - elems [i++] = e; + *elems++ = e; e = e->nextElement; } - - return elems; } void XmlElement::reorderChildElements (XmlElement** const elems, const int num) throw() @@ -15945,7 +15898,7 @@ ThreadPool::ThreadPool (const int numThreads_, { jassert (numThreads_ > 0); // not much point having one of these with no threads in it. - threads = (Thread**) juce_calloc (sizeof (Thread*) * numThreads); + threads.calloc (numThreads); for (int i = numThreads; --i >= 0;) threads[i] = new ThreadPoolThread (*this); @@ -15968,8 +15921,6 @@ ThreadPool::~ThreadPool() threads[i]->stopThread (500); delete threads[i]; } - - juce_free (threads); } void ThreadPool::addJob (ThreadPoolJob* const job) @@ -21403,7 +21354,7 @@ public: lastThreadId (0), dataHandle (0) { - bufferList = (AudioBufferList*) juce_calloc (256); + bufferList.calloc (256, 1); #ifdef WIN32 if (InitializeQTML (0) != noErr) @@ -21461,24 +21412,22 @@ public: if (err != noErr) return; - AudioChannelLayout* const qt_audio_channel_layout - = (AudioChannelLayout*) juce_calloc (output_layout_size); + HeapBlock qt_audio_channel_layout; + qt_audio_channel_layout.calloc (output_layout_size, 1); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout, 0); - qt_audio_channel_layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; + qt_audio_channel_layout[0].mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, - sizeof (qt_audio_channel_layout), + output_layout_size, qt_audio_channel_layout); - juce_free (qt_audio_channel_layout); - err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, @@ -21541,7 +21490,6 @@ public: DisposeMovie (movie); juce_free (bufferList->mBuffers[0].mData); - juce_free (bufferList); #if JUCE_MAC ExitMoviesOnThread (); @@ -21626,7 +21574,7 @@ private: Thread::ThreadID lastThreadId; MovieAudioExtractionRef extractor; AudioStreamBasicDescription inputStreamDesc; - AudioBufferList* bufferList; + HeapBlock bufferList; Handle dataHandle; /*OSErr readMovieStream (long offset, long size, void* dataPtr) @@ -21956,17 +21904,17 @@ public: bwavSize = length; // Broadcast-wav extension chunk.. - BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); + HeapBlock bwav; + bwav.calloc (jmax (length + 1, (int) sizeof (BWAVChunk)), 1); input->read (bwav, length); bwav->copyTo (metadataValues); - juce_free (bwav); } else if (chunkType == chunkName ("smpl")) { - SMPLChunk* const smpl = (SMPLChunk*) juce_calloc (jmax (length + 1, (int) sizeof (SMPLChunk))); + HeapBlock smpl; + smpl.calloc (jmax (length + 1, (int) sizeof (SMPLChunk)), 1); input->read (smpl, length); smpl->copyTo (metadataValues, length); - juce_free (smpl); } else if (chunkEnd <= input->getPosition()) { @@ -25729,18 +25677,35 @@ AudioSampleBuffer::AudioSampleBuffer (const int numChannels_, jassert (numSamples >= 0); jassert (numChannels_ > 0); - allocatedBytes = numChannels * numSamples * sizeof (float) + 32; - allocatedData = (float*) juce_malloc (allocatedBytes); - channels = (float**) juce_malloc ((numChannels_ + 1) * sizeof (float*)); + allocateData(); +} + +AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) throw() + : numChannels (other.numChannels), + size (other.size) +{ + allocateData(); + const int numBytes = size * sizeof (float); + + for (int i = 0; i < numChannels; ++i) + memcpy (channels[i], other.channels[i], numBytes); +} + +void AudioSampleBuffer::allocateData() +{ + const int channelListSize = (numChannels + 1) * sizeof (float*); + allocatedBytes = numChannels * size * sizeof (float) + channelListSize + 32; + allocatedData.malloc (allocatedBytes); + channels = (float**) allocatedData; - float* chan = allocatedData; - for (int i = 0; i < numChannels_; ++i) + float* chan = (float*) (allocatedData + channelListSize); + for (int i = 0; i < numChannels; ++i) { channels[i] = chan; - chan += numSamples; + chan += size; } - channels [numChannels_] = 0; + channels [numChannels] = 0; } AudioSampleBuffer::AudioSampleBuffer (float** dataToReferTo, @@ -25748,84 +25713,49 @@ AudioSampleBuffer::AudioSampleBuffer (float** dataToReferTo, const int numSamples) throw() : numChannels (numChannels_), size (numSamples), - allocatedBytes (0), - allocatedData (0) + allocatedBytes (0) { jassert (numChannels_ > 0); - - // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) - if (numChannels_ < numElementsInArray (preallocatedChannelSpace)) - channels = (float**) preallocatedChannelSpace; - else - channels = (float**) juce_malloc ((numChannels_ + 1) * sizeof (float*)); - - for (int i = 0; i < numChannels_; ++i) - { - // you have to pass in the same number of valid pointers as numChannels - jassert (dataToReferTo[i] != 0); - - channels[i] = dataToReferTo[i]; - } - - channels [numChannels_] = 0; + allocateChannels (dataToReferTo); } void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, - const int numChannels_, - const int numSamples) throw() + const int newNumChannels, + const int newNumSamples) throw() { - jassert (numChannels_ > 0); + jassert (newNumChannels > 0); - juce_free (allocatedData); - allocatedData = 0; allocatedBytes = 0; + allocatedData.free(); - if (numChannels_ > numChannels) - channels = (float**) juce_realloc (channels, (numChannels_ + 1) * sizeof (float*)); - - numChannels = numChannels_; - size = numSamples; - - for (int i = 0; i < numChannels_; ++i) - { - // you have to pass in the same number of valid pointers as numChannels - jassert (dataToReferTo[i] != 0); - - channels[i] = dataToReferTo[i]; - } + numChannels = newNumChannels; + size = newNumSamples; - channels [numChannels_] = 0; + allocateChannels (dataToReferTo); } -AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) throw() - : numChannels (other.numChannels), - size (other.size) +void AudioSampleBuffer::allocateChannels (float** const dataToReferTo) { - channels = (float**) juce_malloc ((other.numChannels + 1) * sizeof (float*)); - - if (other.allocatedData != 0) + // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) + if (numChannels < numElementsInArray (preallocatedChannelSpace)) { - allocatedBytes = numChannels * size * sizeof (float) + 32; - allocatedData = (float*) juce_malloc (allocatedBytes); - - memcpy (allocatedData, other.allocatedData, allocatedBytes); - - float* chan = allocatedData; - for (int i = 0; i < numChannels; ++i) - { - channels[i] = chan; - chan += size; - } - - channels [numChannels] = 0; + channels = (float**) preallocatedChannelSpace; } else { - allocatedData = 0; - allocatedBytes = 0; + allocatedData.malloc (numChannels + 1, sizeof (float*)); + channels = (float**) allocatedData; + } + + for (int i = 0; i < numChannels; ++i) + { + // you have to pass in the same number of valid pointers as numChannels + jassert (dataToReferTo[i] != 0); - memcpy (channels, other.channels, sizeof (channels)); + channels[i] = dataToReferTo[i]; } + + channels [numChannels] = 0; } const AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) throw() @@ -25845,10 +25775,6 @@ const AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& AudioSampleBuffer::~AudioSampleBuffer() throw() { - juce_free (allocatedData); - - if (channels != (float**) preallocatedChannelSpace) - juce_free (channels); } void AudioSampleBuffer::setSize (const int newNumChannels, @@ -25861,26 +25787,29 @@ void AudioSampleBuffer::setSize (const int newNumChannels, if (newNumSamples != size || newNumChannels != numChannels) { - const int newTotalBytes = newNumChannels * newNumSamples * sizeof (float) + 32; + const int channelListSize = (newNumChannels + 1) * sizeof (float*); + const int newTotalBytes = (newNumChannels * newNumSamples * sizeof (float)) + channelListSize + 32; if (keepExistingContent) { - float* const newData = (clearExtraSpace) ? (float*) juce_calloc (newTotalBytes) - : (float*) juce_malloc (newTotalBytes); + HeapBlock newData; + newData.allocate (newTotalBytes, clearExtraSpace); - const int sizeToCopy = sizeof (float) * jmin (newNumSamples, size); + const int numChansToCopy = jmin (numChannels, newNumChannels); + const int numBytesToCopy = sizeof (float) * jmin (newNumSamples, size); - for (int i = jmin (newNumChannels, numChannels); --i >= 0;) + float** const newChannels = (float**) newData; + float* newChan = (float*) (newData + channelListSize); + for (int i = 0; i < numChansToCopy; ++i) { - memcpy (newData + i * newNumSamples, - channels[i], - sizeToCopy); + memcpy (newChan, channels[i], numBytesToCopy); + newChannels[i] = newChan; + newChan += newNumSamples; } - juce_free (allocatedData); - - allocatedData = newData; + allocatedData.swapWith (newData); allocatedBytes = newTotalBytes; + channels = (float**) allocatedData; } else { @@ -25891,29 +25820,22 @@ void AudioSampleBuffer::setSize (const int newNumChannels, } else { - juce_free (allocatedData); - - allocatedData = (clearExtraSpace) ? (float*) juce_calloc (newTotalBytes) - : (float*) juce_malloc (newTotalBytes); allocatedBytes = newTotalBytes; + allocatedData.allocate (newTotalBytes, clearExtraSpace); + channels = (float**) allocatedData; } - } - - size = newNumSamples; - - if (newNumChannels > numChannels) - channels = (float**) juce_realloc (channels, (newNumChannels + 1) * sizeof (float*)); - - numChannels = newNumChannels; - float* chan = allocatedData; - for (int i = 0; i < newNumChannels; ++i) - { - channels[i] = chan; - chan += size; + float* chan = (float*) (allocatedData + channelListSize); + for (int i = 0; i < newNumChannels; ++i) + { + channels[i] = chan; + chan += newNumSamples; + } } channels [newNumChannels] = 0; + size = newNumSamples; + numChannels = newNumChannels; } } @@ -26367,7 +26289,8 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, } else { - chans[0] = (int*) juce_malloc (sizeof (int) * numSamples * 2); + HeapBlock tempBuffer (numSamples * 2); + chans[0] = tempBuffer; if (numChannels > 1) chans[1] = chans[0] + numSamples; @@ -26399,8 +26322,6 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, } writer->write ((const int**) chans, numSamples); - - juce_free (chans[0]); } } } @@ -30321,7 +30242,7 @@ private: CriticalSection lock; bool initialised, wantsMidiMessages, wasPlaying; - AudioBufferList* outputBufferList; + HeapBlock outputBufferList; AudioTimeStamp timeStamp; AudioSampleBuffer* currentBuffer; @@ -30415,7 +30336,6 @@ AudioUnitPluginInstance::AudioUnitPluginInstance (const String& fileOrIdentifier initialised (false), wantsMidiMessages (false), audioUnit (0), - outputBufferList (0), currentBuffer (0) { try @@ -30459,8 +30379,6 @@ AudioUnitPluginInstance::~AudioUnitPluginInstance() audioUnit = 0; } } - - juce_free (outputBufferList); } bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIdentifier) @@ -30639,8 +30557,7 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_, kAudioUnitScope_Output, 0, &stream, sizeof (stream)); - juce_free (outputBufferList); - outputBufferList = (AudioBufferList*) juce_calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1)); + outputBufferList.calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1), 1); outputBufferList->mNumberBuffers = numOuts; for (int i = numOuts; --i >= 0;) @@ -30664,8 +30581,7 @@ void AudioUnitPluginInstance::releaseResources() AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); - juce_free (outputBufferList); - outputBufferList = 0; + outputBufferList.free(); currentBuffer = 0; } } @@ -30935,7 +30851,8 @@ private: && AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr) { - AudioUnitCocoaViewInfo* info = (AudioUnitCocoaViewInfo*) juce_calloc (dataSize); + HeapBlock info; + info.calloc (dataSize, 1); if (AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, info, &dataSize) == noErr) @@ -30960,8 +30877,6 @@ private: CFRelease (info->mCocoaAUViewBundleLocation); } } - - juce_free (info); } if (createGenericViewIfNeeded && (pluginView == 0)) @@ -31645,7 +31560,7 @@ class VSTMidiEventList public: VSTMidiEventList() - : events (0), numEventsUsed (0), numEventsAllocated (0) + : numEventsUsed (0), numEventsAllocated (0) { } @@ -31740,9 +31655,9 @@ public: const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; if (events == 0) - events = (VstEvents*) juce_calloc (size); + events.calloc (size, 1); else - events = (VstEvents*) juce_realloc (events, size); + events.realloc (size, 1); for (int i = numEventsAllocated; i < numEventsNeeded; ++i) { @@ -31772,14 +31687,13 @@ public: juce_free (e); } - juce_free (events); - events = 0; + events.free(); numEventsUsed = 0; numEventsAllocated = 0; } } - VstEvents* events; + HeapBlock events; private: int numEventsUsed, numEventsAllocated; @@ -32425,7 +32339,7 @@ private: MidiBuffer incomingMidi; VSTMidiEventList midiEventsToSend; VstTimeInfo vstHostTime; - float** channels; + HeapBlock channels; ReferenceCountedObjectPtr module; @@ -32462,7 +32376,6 @@ VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr initialDelay); - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (16, getNumOutputChannels() + 2, getNumInputChannels() + 2)); + channels.calloc (jmax (16, getNumOutputChannels(), getNumInputChannels()) + 2); vstHostTime.tempo = 120.0; vstHostTime.timeSigNumerator = 4; @@ -32671,8 +32580,7 @@ void VSTPluginInstance::releaseResources() incomingMidi.clear(); midiEventsToSend.freeEvents(); - juce_free (channels); - channels = 0; + channels.free(); } void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, @@ -35410,7 +35318,7 @@ public: totalChans (jmax (1, totalChans_)), midiBufferToUse (midiBufferToUse_) { - channels = (float**) juce_calloc (sizeof (float*) * totalChans); + channels.calloc (totalChans); while (audioChannelsToUse.size() < totalChans) audioChannelsToUse.add (0); @@ -35418,7 +35326,6 @@ public: ~ProcessBufferOp() throw() { - juce_free (channels); } void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() @@ -35436,7 +35343,7 @@ public: private: Array audioChannelsToUse; - float** channels; + HeapBlock channels; int totalChans; int midiBufferToUse; @@ -49727,6 +49634,7 @@ void Slider::mouseDown (const MouseEvent& e) menuShown = true; PopupMenu m; + m.setLookAndFeel (&getLookAndFeel()); m.addItem (1, TRANS ("velocity-sensitive mode"), true, isVelocityBased); m.addSeparator(); @@ -53341,6 +53249,7 @@ void TextEditor::mouseDown (const MouseEvent& e) else { PopupMenu m; + m.setLookAndFeel (&getLookAndFeel()); addPopupMenuItems (m, &e); menuActive = true; @@ -53359,7 +53268,7 @@ void TextEditor::mouseDrag (const MouseEvent& e) { if (! (popupMenuEnabled && e.mods.isPopupMenu())) { - moveCursorTo (getTextIndexAt (e.x, e.y), true); + moveCursorTo (getTextIndexAt (e.x, e.y), true); } } } @@ -75159,7 +75068,7 @@ void MidiKeyboardComponent::resetAnyKeysInUse() void MidiKeyboardComponent::updateNoteUnderMouse (int x, int y) { - float mousePositionVelocity; + float mousePositionVelocity = 0.0f; const int newNote = (mouseDragging || isMouseOver()) ? xyToNote (x, y, mousePositionVelocity) : -1; @@ -79409,7 +79318,7 @@ const Colour ColourGradient::getColourAtPosition (const float position) const th return col1.interpolatedWith (col2, (integerPos - pos1) / (float) (pos2 - pos1)); } -PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, int& numEntries) const throw() +int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock & lookupTable) const throw() { #ifdef JUCE_DEBUG // trying to use the object without setting its co-ordinates? Have a careful read of @@ -79424,9 +79333,8 @@ PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, transform.transformPoint (tx2, ty2); const double distance = juce_hypot (tx1 - tx2, ty1 - ty2); - numEntries = jlimit (1, (numColours - 1) << 8, 3 * (int) distance); - - PixelARGB* const lookupTable = (PixelARGB*) juce_calloc (numEntries * sizeof (PixelARGB)); + const int numEntries = jlimit (1, (numColours - 1) << 8, 3 * (int) distance); + lookupTable.malloc (numEntries); if (numColours >= 2) { @@ -79462,7 +79370,7 @@ PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, jassertfalse // no colours specified! } - return lookupTable; + return numEntries; } bool ColourGradient::isOpaque() const throw() @@ -79812,10 +79720,10 @@ EdgeTable::EdgeTable (const Rectangle& bounds_, lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), needToCheckEmptinesss (true) { - table = (int*) juce_malloc ((bounds.getHeight() + 1) * lineStrideElements * sizeof (int)); + table.malloc ((bounds.getHeight() + 1) * lineStrideElements); int* t = table; - int i = 0; - for (i = bounds.getHeight(); --i >= 0;) + + for (int i = bounds.getHeight(); --i >= 0;) { *t = 0; t += lineStrideElements; @@ -79877,53 +79785,7 @@ EdgeTable::EdgeTable (const Rectangle& bounds_, } } - // Convert the table from relative windings to absolute levels.. - int* lineStart = table; - - for (i = bounds.getHeight(); --i >= 0;) - { - int* line = lineStart; - lineStart += lineStrideElements; - - int num = *line; - if (num == 0) - continue; - - int level = 0; - - if (path.isUsingNonZeroWinding()) - { - while (--num > 0) - { - line += 2; - level += *line; - int corrected = abs (level); - if (corrected >> 8) - corrected = 255; - - *line = corrected; - } - } - else - { - while (--num > 0) - { - line += 2; - level += *line; - int corrected = abs (level); - if (corrected >> 8) - { - corrected &= 511; - if (corrected >> 8) - corrected = 511 - corrected; - } - - *line = corrected; - } - } - - line[2] = 0; // force the last level to 0, just in case something went wrong in creating the table - } + sanitiseLevels (path.isUsingNonZeroWinding()); } EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() @@ -79932,8 +79794,8 @@ EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), needToCheckEmptinesss (true) { - table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); - *table = 0; + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); + table[0] = 0; const int x1 = rectangleToAdd.getX() << 8; const int x2 = rectangleToAdd.getRight() << 8; @@ -79950,6 +79812,40 @@ EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() } } +EdgeTable::EdgeTable (const RectangleList& rectanglesToAdd) throw() + : bounds (rectanglesToAdd.getBounds()), + maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), + lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), + needToCheckEmptinesss (true) +{ + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); + + int* t = table; + for (int i = bounds.getHeight(); --i >= 0;) + { + *t = 0; + t += lineStrideElements; + } + + for (RectangleList::Iterator iter (rectanglesToAdd); iter.next();) + { + const Rectangle* const r = iter.getRectangle(); + + const int x1 = r->getX() << 8; + const int x2 = r->getRight() << 8; + int y = r->getY() - bounds.getY(); + + for (int j = r->getHeight(); --j >= 0;) + { + addEdgePoint (x1, y, 255); + addEdgePoint (x2, y, -255); + ++y; + } + } + + sanitiseLevels (true); +} + EdgeTable::EdgeTable (const float x, const float y, const float w, const float h) throw() : bounds (Rectangle ((int) floorf (x), roundFloatToInt (y * 256.0f) >> 8, 2 + (int) w, 2 + (int) h)), maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), @@ -79957,8 +79853,8 @@ EdgeTable::EdgeTable (const float x, const float y, const float w, const float h needToCheckEmptinesss (true) { jassert (w > 0 && h > 0); - table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); - *table = 0; + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); + table[0] = 0; const int x1 = roundFloatToInt (x * 256.0f); const int x2 = roundFloatToInt ((x + w) * 256.0f); @@ -80033,22 +79929,69 @@ EdgeTable::EdgeTable (const EdgeTable& other) throw() const EdgeTable& EdgeTable::operator= (const EdgeTable& other) throw() { - juce_free (table); - bounds = other.bounds; maxEdgesPerLine = other.maxEdgesPerLine; lineStrideElements = other.lineStrideElements; needToCheckEmptinesss = other.needToCheckEmptinesss; - const int tableSize = jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int); - table = (int*) juce_malloc (tableSize); + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight()); return *this; } EdgeTable::~EdgeTable() throw() { - juce_free (table); +} + +void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) throw() +{ + // Convert the table from relative windings to absolute levels.. + int* lineStart = table; + + for (int i = bounds.getHeight(); --i >= 0;) + { + int* line = lineStart; + lineStart += lineStrideElements; + + int num = *line; + if (num == 0) + continue; + + int level = 0; + + if (useNonZeroWinding) + { + while (--num > 0) + { + line += 2; + level += *line; + int corrected = abs (level); + if (corrected >> 8) + corrected = 255; + + *line = corrected; + } + } + else + { + while (--num > 0) + { + line += 2; + level += *line; + int corrected = abs (level); + if (corrected >> 8) + { + corrected &= 511; + if (corrected >> 8) + corrected = 511 - corrected; + } + + *line = corrected; + } + } + + line[2] = 0; // force the last level to 0, just in case something went wrong in creating the table + } } void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) throw() @@ -80059,12 +80002,12 @@ void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) throw() jassert (bounds.getHeight() > 0); const int newLineStrideElements = maxEdgesPerLine * 2 + 1; - int* const newTable = (int*) juce_malloc (bounds.getHeight() * newLineStrideElements * sizeof (int)); + + HeapBlock newTable (bounds.getHeight() * newLineStrideElements); copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight()); - juce_free (table); - table = newTable; + table.swapWith (newTable); lineStrideElements = newLineStrideElements; } } @@ -82296,12 +82239,11 @@ public: maxY (srcData_.height - 1), scratchSize (2048) { - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } ~TransformedImageFillEdgeTableRenderer() throw() { - juce_free (scratchBuffer); } forcedinline void setEdgeTableYPos (const int newY) throw() @@ -82326,8 +82268,7 @@ public: if (width > scratchSize) { scratchSize = width; - juce_free (scratchBuffer); - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } SrcPixelType* span = scratchBuffer; @@ -82358,8 +82299,7 @@ public: if (width > scratchSize) { scratchSize = width; - juce_free (scratchBuffer); - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } uint8* mask = (uint8*) scratchBuffer; @@ -82667,7 +82607,7 @@ private: const int pixelOffsetInt, maxX, maxY; int y; DestPixelType* linePixels; - SrcPixelType* scratchBuffer; + HeapBlock scratchBuffer; int scratchSize; TransformedImageFillEdgeTableRenderer (const TransformedImageFillEdgeTableRenderer&); @@ -82708,13 +82648,10 @@ public: bool clipToRectangleList (const RectangleList& r) throw() { dupeEdgeTableIfMultiplyReferenced(); - RectangleList temp (r); - temp.offsetAll (xOffset, yOffset); - RectangleList totalArea (edgeTable->edgeTable.getMaximumBounds()); - totalArea.subtract (temp); - - for (RectangleList::Iterator i (totalArea); i.next();) - edgeTable->edgeTable.excludeRectangle (*i.getRectangle()); + RectangleList offsetList (r); + offsetList.offsetAll (xOffset, yOffset); + EdgeTable e2 (offsetList); + edgeTable->edgeTable.clipToEdgeTable (e2); return ! edgeTable->edgeTable.isEmpty(); } @@ -82758,8 +82695,8 @@ public: transform = AffineTransform::identity; } - int numLookupEntries; - PixelARGB* const lookupTable = g2.createLookupTable (transform, numLookupEntries); + HeapBlock lookupTable; + const int numLookupEntries = g2.createLookupTable (transform, lookupTable); jassert (numLookupEntries > 0); switch (image.getFormat()) @@ -82768,8 +82705,6 @@ public: case Image::RGB: renderGradient (et, destData, g2, transform, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) 0); break; default: renderGradient (et, destData, g2, transform, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) 0); break; } - - juce_free (lookupTable); } else if (fillType.isTiledImage()) { @@ -89693,10 +89628,9 @@ void Path::writePathToStream (OutputStream& dest) const const String Path::toString() const { - String s; - s.preallocateStorage (numElements * 4); + MemoryOutputStream s (2048, 2048); if (! useNonZeroWinding) - s << T("a "); + s << "a "; int i = 0; float lastMarker = 0.0f; @@ -89704,38 +89638,38 @@ const String Path::toString() const while (i < numElements) { const float marker = data.elements [i++]; - tchar markerChar = 0; + char markerChar = 0; int numCoords = 0; if (marker == moveMarker) { - markerChar = T('m'); + markerChar = 'm'; numCoords = 2; } else if (marker == lineMarker) { - markerChar = T('l'); + markerChar = 'l'; numCoords = 2; } else if (marker == quadMarker) { - markerChar = T('q'); + markerChar = 'q'; numCoords = 4; } else if (marker == cubicMarker) { - markerChar = T('c'); + markerChar = 'c'; numCoords = 6; } else { jassert (marker == closeSubPathMarker); - markerChar = T('z'); + markerChar = 'z'; } if (marker != lastMarker) { - s << markerChar << T(' '); + s << markerChar << ' '; lastMarker = marker; } @@ -89743,17 +89677,28 @@ const String Path::toString() const { String n (data.elements [i++], 3); - while (n.endsWithChar (T('0'))) - n = n.dropLastCharacters (1); + if (n.endsWithChar (T('0'))) + { + do + { + n = n.dropLastCharacters (1); + } while (n.endsWithChar (T('0'))); - if (n.endsWithChar (T('.'))) - n = n.dropLastCharacters (1); + if (n.endsWithChar (T('.'))) + n = n.dropLastCharacters (1); + } - s << n << T(' '); + s << n << ' '; } } - return s.trimEnd(); + const char* const result = (const char*) s.getData(); + int len = s.getDataSize(); + + while (len > 0 && CharacterFunctions::isWhitespace (result [len - 1])) + --len; + + return String (result, len); } static const String nextToken (const tchar*& t) @@ -89939,17 +89884,16 @@ PathFlatteningIterator::PathFlatteningIterator (const Path& path_, tolerence (tolerence_ * tolerence_), subPathCloseX (0), subPathCloseY (0), + stackBase (32), index (0), stackSize (32) { - stackBase = (float*) juce_malloc (stackSize * sizeof (float)); isIdentityTransform = transform.isIdentity(); stackPos = stackBase; } PathFlatteningIterator::~PathFlatteningIterator() throw() { - juce_free (stackBase); } bool PathFlatteningIterator::next() throw() @@ -90050,7 +89994,7 @@ bool PathFlatteningIterator::next() throw() if (offset >= stackSize - 10) { stackSize <<= 1; - stackBase = (float*) juce_realloc (stackBase, stackSize * sizeof (float)); + stackBase.realloc (stackSize); stackPos = stackBase + offset; } @@ -90100,7 +90044,7 @@ bool PathFlatteningIterator::next() throw() if (offset >= stackSize - 16) { stackSize <<= 1; - stackBase = (float*) juce_realloc (stackBase, stackSize * sizeof (float)); + stackBase.realloc (stackSize); stackPos = stackBase + offset; } @@ -92093,10 +92037,9 @@ Image::Image (const PixelFormat format_, pixelStride = (format == RGB) ? 3 : ((format == ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, imageWidth_) + 3) & ~3; - const int dataSize = lineStride * jmax (1, imageHeight_); - imageData = (uint8*) (clearImage ? juce_calloc (dataSize) - : juce_malloc (dataSize)); + imageDataAllocated.allocate (lineStride * jmax (1, imageHeight_), clearImage); + imageData = imageDataAllocated; } Image::Image (const Image& other) @@ -92106,9 +92049,9 @@ Image::Image (const Image& other) { pixelStride = (format == RGB) ? 3 : ((format == ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, imageWidth) + 3) & ~3; - const int dataSize = lineStride * jmax (1, imageHeight); - imageData = (uint8*) juce_malloc (dataSize); + imageDataAllocated.malloc (lineStride * jmax (1, imageHeight)); + imageData = imageDataAllocated; BitmapData srcData (other, 0, 0, imageWidth, imageHeight); setPixelData (0, 0, imageWidth, imageHeight, srcData.data, srcData.lineStride); @@ -92116,7 +92059,6 @@ Image::Image (const Image& other) Image::~Image() { - juce_free (imageData); } LowLevelGraphicsContext* Image::createLowLevelContext() @@ -92729,22 +92671,14 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE ImageConvolutionKernel::ImageConvolutionKernel (const int size_) throw() - : size (size_) + : values (size_ * size_), + size (size_) { - values = new float* [size]; - - for (int i = size; --i >= 0;) - values[i] = new float [size]; - clear(); } ImageConvolutionKernel::~ImageConvolutionKernel() throw() { - for (int i = size; --i >= 0;) - delete[] values[i]; - - delete[] values; } void ImageConvolutionKernel::setKernelValue (const int x, @@ -92754,7 +92688,7 @@ void ImageConvolutionKernel::setKernelValue (const int x, if (((unsigned int) x) < (unsigned int) size && ((unsigned int) y) < (unsigned int) size) { - values[x][y] = value; + values [x + y * size] = value; } else { @@ -92764,27 +92698,24 @@ void ImageConvolutionKernel::setKernelValue (const int x, void ImageConvolutionKernel::clear() throw() { - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - values[x][y] = 0; + for (int i = size * size; --i >= 0;) + values[i] = 0; } void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum) throw() { double currentTotal = 0.0; - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - currentTotal += values[x][y]; + for (int i = size * size; --i >= 0;) + currentTotal += values[i]; rescaleAllValues ((float) (desiredTotalSum / currentTotal)); } void ImageConvolutionKernel::rescaleAllValues (const float multiplier) throw() { - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - values[x][y] *= multiplier; + for (int i = size * size; --i >= 0;) + values[i] *= multiplier; } void ImageConvolutionKernel::createGaussianBlur (const float radius) throw() @@ -92799,7 +92730,7 @@ void ImageConvolutionKernel::createGaussianBlur (const float radius) throw() const int cx = x - centre; const int cy = y - centre; - values[x][y] = (float) exp (radiusFactor * (cx * cx + cy * cy)); + values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy)); } } @@ -92884,7 +92815,7 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, if (sx >= 0) { - const float kernelMult = values[xx][yy]; + const float kernelMult = values [xx + yy * size]; c1 += kernelMult * *src++; c2 += kernelMult * *src++; c3 += kernelMult * *src++; @@ -92939,7 +92870,7 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, if (sx >= 0) { - const float kernelMult = values[xx][yy]; + const float kernelMult = values [xx + yy * size]; c1 += kernelMult * *src++; c2 += kernelMult * *src++; c3 += kernelMult * *src++; @@ -95336,7 +95267,7 @@ using namespace zlibNamespace; class GZIPCompressorHelper { private: - z_stream* stream; + HeapBlock stream; uint8* data; int dataSize, compLevel, strategy; bool setParams; @@ -95353,7 +95284,7 @@ public: finished (false), shouldFinish (false) { - stream = (z_stream*) juce_calloc (sizeof (z_stream)); + stream.calloc (1); if (deflateInit2 (stream, compLevel, @@ -95362,18 +95293,14 @@ public: 8, strategy) != Z_OK) { - juce_free (stream); - stream = 0; + stream.free(); } } ~GZIPCompressorHelper() { if (stream != 0) - { deflateEnd (stream); - juce_free (stream); - } } bool needsInput() const throw() @@ -95428,14 +95355,14 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest const bool deleteDestStream_, const bool noWrap) : destStream (destStream_), - deleteDestStream (deleteDestStream_) + deleteDestStream (deleteDestStream_), + buffer (gzipCompBufferSize) { if (compressionLevel < 1 || compressionLevel > 9) compressionLevel = -1; helper = new GZIPCompressorHelper (compressionLevel, noWrap); - buffer = (uint8*) juce_malloc (gzipCompBufferSize); } GZIPCompressorOutputStream::~GZIPCompressorOutputStream() @@ -95445,8 +95372,6 @@ GZIPCompressorOutputStream::~GZIPCompressorOutputStream() GZIPCompressorHelper* const h = (GZIPCompressorHelper*) helper; delete h; - juce_free (buffer); - if (deleteDestStream) delete destStream; } @@ -102740,7 +102665,7 @@ using namespace zlibNamespace; class GZIPDecompressHelper { private: - z_stream* stream; + HeapBlock stream; uint8* data; int dataSize; @@ -102754,13 +102679,12 @@ public: needsDictionary (false), error (false) { - stream = (z_stream*) juce_calloc (sizeof (z_stream)); + stream.calloc (1); if (inflateInit2 (stream, (noWrap) ? -MAX_WBITS : MAX_WBITS) != Z_OK) { - juce_free (stream); - stream = 0; + stream.free(); error = true; finished = true; } @@ -102769,10 +102693,7 @@ public: ~GZIPDecompressHelper() throw() { if (stream != 0) - { inflateEnd (stream); - juce_free (stream); - } } bool needsInput() const throw() { return dataSize <= 0; } @@ -102835,16 +102756,14 @@ GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream* const sou isEof (false), activeBufferSize (0), originalSourcePos (sourceStream_->getPosition()), - currentPos (0) + currentPos (0), + buffer (gzipDecompBufferSize) { - buffer = (uint8*) juce_malloc (gzipDecompBufferSize); helper = new GZIPDecompressHelper (noWrap_); } GZIPDecompressorInputStream::~GZIPDecompressorInputStream() { - juce_free (buffer); - if (deleteSourceWhenDestroyed) delete sourceStream; @@ -208655,7 +208574,8 @@ bool juce_writeJPEGImageToStream (const Image& image, jpegCompStruct.dest = &dest; dest.output = &out; - dest.buffer = (char*) juce_malloc (bufferSize); + HeapBlock tempBuffer (bufferSize); + dest.buffer = (char*) tempBuffer; dest.next_output_byte = (JOCTET*) dest.buffer; dest.free_in_buffer = bufferSize; dest.init_destination = jpegWriteInit; @@ -208711,8 +208631,6 @@ bool juce_writeJPEGImageToStream (const Image& image, jpeg_finish_compress (&jpegCompStruct); jpeg_destroy_compress (&jpegCompStruct); - juce_free (dest.buffer); - out.flush(); return true; @@ -234224,17 +234142,17 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() || pngInfoStruct->num_trans > 0; // Load the image into a temp buffer in the pnglib format.. - uint8* const tempBuffer = (uint8*) juce_malloc (height * (width << 2)); + HeapBlock tempBuffer (height * (width << 2)); - png_bytepp rows = (png_bytepp) juce_malloc (sizeof (png_bytep) * height); - int y; - for (y = (int) height; --y >= 0;) - rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); + { + HeapBlock rows (height); + for (int y = (int) height; --y >= 0;) + rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); - png_read_image (pngReadStruct, rows); - png_read_end (pngReadStruct, pngInfoStruct); + png_read_image (pngReadStruct, rows); + png_read_end (pngReadStruct, pngInfoStruct); + } - juce_free (rows); png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); // now convert the data to a juce image format.. @@ -234247,7 +234165,7 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() uint8* srcRow = tempBuffer; uint8* destRow = destData.data; - for (y = 0; y < (int) height; ++y) + for (int y = 0; y < (int) height; ++y) { const uint8* src = srcRow; srcRow += (width << 2); @@ -234274,8 +234192,6 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() } } } - - juce_free (tempBuffer); } return image; @@ -234318,7 +234234,7 @@ bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_bytep rowData = (png_bytep) juce_malloc (width * 4 * sizeof (png_byte)); + HeapBlock rowData (width * 4); png_color_8 sig_bit; sig_bit.red = 8; @@ -234367,8 +234283,6 @@ bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() png_write_rows (pngWriteStruct, &rowData, 1); } - juce_free (rowData); - png_write_end (pngWriteStruct, pngInfoStruct); png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct); @@ -235724,7 +235638,8 @@ const String File::getVersion() const throw() DWORD handle = 0; DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle); - void* buffer = juce_calloc (bufferSize); + HeapBlock buffer; + buffer.calloc (bufferSize); if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer)) { @@ -235741,7 +235656,6 @@ const String File::getVersion() const throw() } } - juce_free (buffer); return result; } @@ -237149,7 +237063,6 @@ public: { DeleteDC (hdc); DeleteObject (hBitmap); - imageData = 0; // to stop the base class freeing this } void blitToWindow (HWND hwnd, HDC dc, const bool transparent, @@ -238733,408 +238646,408 @@ public: private: LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) { + if (isValidPeer (this)) { - if (isValidPeer (this)) + switch (message) { - switch (message) - { - case WM_NCHITTEST: - if (hasTitleBar()) - break; - return HTCLIENT; + case WM_NCHITTEST: + if ((styleFlags & windowIgnoresMouseClicks) != 0) + return HTTRANSPARENT; + + if (hasTitleBar()) + break; + + return HTCLIENT; + + case WM_PAINT: + handlePaintMessage(); + return 0; - case WM_PAINT: + case WM_NCPAINT: + if (wParam != 1) handlePaintMessage(); - return 0; - case WM_NCPAINT: - if (wParam != 1) - handlePaintMessage(); + if (hasTitleBar()) + break; - if (hasTitleBar()) - break; + return 0; - return 0; + case WM_ERASEBKGND: + case WM_NCCALCSIZE: + if (hasTitleBar()) + break; - case WM_ERASEBKGND: - case WM_NCCALCSIZE: - if (hasTitleBar()) - break; + return 1; - return 1; + case WM_MOUSEMOVE: + doMouseMove (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)); + return 0; - case WM_MOUSEMOVE: - doMouseMove (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)); - return 0; + case WM_MOUSELEAVE: + doMouseExit(); + return 0; - case WM_MOUSELEAVE: - doMouseExit(); - return 0; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + doMouseDown (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); + return 0; - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - doMouseDown (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); - return 0; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + doMouseUp (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); + return 0; - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - doMouseUp (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); - return 0; + case WM_CAPTURECHANGED: + doCaptureChanged(); + return 0; - case WM_CAPTURECHANGED: - doCaptureChanged(); - return 0; + case WM_NCMOUSEMOVE: + if (hasTitleBar()) + break; - case WM_NCMOUSEMOVE: - if (hasTitleBar()) - break; + return 0; - return 0; + case 0x020A: /* WM_MOUSEWHEEL */ + doMouseWheel (wParam, true); + return 0; - case 0x020A: /* WM_MOUSEWHEEL */ - doMouseWheel (wParam, true); - return 0; + case 0x020E: /* WM_MOUSEHWHEEL */ + doMouseWheel (wParam, false); + return 0; - case 0x020E: /* WM_MOUSEHWHEEL */ - doMouseWheel (wParam, false); - return 0; + case WM_WINDOWPOSCHANGING: + if ((styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)) + { + WINDOWPOS* const wp = (WINDOWPOS*) lParam; - case WM_WINDOWPOSCHANGING: - if ((styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)) + if ((wp->flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) { - WINDOWPOS* const wp = (WINDOWPOS*) lParam; - - if ((wp->flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) + if (constrainer != 0) { - if (constrainer != 0) - { - const Rectangle current (component->getX() - windowBorder.getLeft(), - component->getY() - windowBorder.getTop(), - component->getWidth() + windowBorder.getLeftAndRight(), - component->getHeight() + windowBorder.getTopAndBottom()); - - constrainer->checkBounds (wp->x, wp->y, wp->cx, wp->cy, - current, - Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(), - wp->y != current.getY() && wp->y + wp->cy == current.getBottom(), - wp->x != current.getX() && wp->x + wp->cx == current.getRight(), - wp->y == current.getY() && wp->y + wp->cy != current.getBottom(), - wp->x == current.getX() && wp->x + wp->cx != current.getRight()); - } + const Rectangle current (component->getX() - windowBorder.getLeft(), + component->getY() - windowBorder.getTop(), + component->getWidth() + windowBorder.getLeftAndRight(), + component->getHeight() + windowBorder.getTopAndBottom()); + + constrainer->checkBounds (wp->x, wp->y, wp->cx, wp->cy, + current, + Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(), + wp->y != current.getY() && wp->y + wp->cy == current.getBottom(), + wp->x != current.getX() && wp->x + wp->cx == current.getRight(), + wp->y == current.getY() && wp->y + wp->cy != current.getBottom(), + wp->x == current.getX() && wp->x + wp->cx != current.getRight()); } } + } - return 0; + return 0; - case WM_WINDOWPOSCHANGED: - handleMovedOrResized(); + case WM_WINDOWPOSCHANGED: + handleMovedOrResized(); - if (dontRepaint) - break; // needed for non-accelerated openGL windows to draw themselves correctly.. - else - return 0; + if (dontRepaint) + break; // needed for non-accelerated openGL windows to draw themselves correctly.. - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - if (doKeyDown (wParam)) - return 0; + return 0; - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - if (doKeyUp (wParam)) - return 0; - - break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (doKeyDown (wParam)) + return 0; - case WM_CHAR: - if (doKeyChar ((int) wParam, lParam)) - return 0; + break; - break; + case WM_KEYUP: + case WM_SYSKEYUP: + if (doKeyUp (wParam)) + return 0; - case WM_APPCOMMAND: - if (doAppCommand (lParam)) - return TRUE; + break; - break; + case WM_CHAR: + if (doKeyChar ((int) wParam, lParam)) + return 0; - case WM_SETFOCUS: - updateKeyModifiers(); - handleFocusGain(); - break; + break; - case WM_KILLFOCUS: - if (hasCreatedCaret) - { - hasCreatedCaret = false; - DestroyCaret(); - } + case WM_APPCOMMAND: + if (doAppCommand (lParam)) + return TRUE; - handleFocusLoss(); - break; + break; - case WM_ACTIVATEAPP: - // Windows does weird things to process priority when you swap apps, - // so this forces an update when the app is brought to the front - if (wParam != FALSE) - juce_repeatLastProcessPriority(); - else - Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus + case WM_SETFOCUS: + updateKeyModifiers(); + handleFocusGain(); + break; - juce_CheckCurrentlyFocusedTopLevelWindow(); - modifiersAtLastCallback = -1; - return 0; + case WM_KILLFOCUS: + if (hasCreatedCaret) + { + hasCreatedCaret = false; + DestroyCaret(); + } - case WM_ACTIVATE: - if (LOWORD (wParam) == WA_ACTIVE || LOWORD (wParam) == WA_CLICKACTIVE) - { - modifiersAtLastCallback = -1; - updateKeyModifiers(); + handleFocusLoss(); + break; - if (isMinimised()) - { - component->repaint(); - handleMovedOrResized(); + case WM_ACTIVATEAPP: + // Windows does weird things to process priority when you swap apps, + // so this forces an update when the app is brought to the front + if (wParam != FALSE) + juce_repeatLastProcessPriority(); + else + Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus - if (! isValidMessageListener()) - return 0; - } + juce_CheckCurrentlyFocusedTopLevelWindow(); + modifiersAtLastCallback = -1; + return 0; - if (LOWORD (wParam) == WA_CLICKACTIVE - && component->isCurrentlyBlockedByAnotherModalComponent()) - { - int mx, my; - component->getMouseXYRelative (mx, my); - Component* const underMouse = component->getComponentAt (mx, my); + case WM_ACTIVATE: + if (LOWORD (wParam) == WA_ACTIVE || LOWORD (wParam) == WA_CLICKACTIVE) + { + modifiersAtLastCallback = -1; + updateKeyModifiers(); - if (underMouse != 0 && underMouse->isCurrentlyBlockedByAnotherModalComponent()) - Component::getCurrentlyModalComponent()->inputAttemptWhenModal(); + if (isMinimised()) + { + component->repaint(); + handleMovedOrResized(); + if (! isValidMessageListener()) return 0; - } + } - handleBroughtToFront(); + if (LOWORD (wParam) == WA_CLICKACTIVE + && component->isCurrentlyBlockedByAnotherModalComponent()) + { + int mx, my; + component->getMouseXYRelative (mx, my); + Component* const underMouse = component->getComponentAt (mx, my); - if (component->isCurrentlyBlockedByAnotherModalComponent()) - Component::getCurrentlyModalComponent()->toFront (true); + if (underMouse != 0 && underMouse->isCurrentlyBlockedByAnotherModalComponent()) + Component::getCurrentlyModalComponent()->inputAttemptWhenModal(); return 0; } - break; + handleBroughtToFront(); - case WM_NCACTIVATE: - // while a temporary window is being shown, prevent Windows from deactivating the - // title bars of our main windows. - if (wParam == 0 && ! shouldDeactivateTitleBar) - wParam = TRUE; // change this and let it get passed to the DefWindowProc. + if (component->isCurrentlyBlockedByAnotherModalComponent()) + Component::getCurrentlyModalComponent()->toFront (true); - break; + return 0; + } - case WM_MOUSEACTIVATE: - if (! component->getMouseClickGrabsKeyboardFocus()) - return MA_NOACTIVATE; + break; - break; + case WM_NCACTIVATE: + // while a temporary window is being shown, prevent Windows from deactivating the + // title bars of our main windows. + if (wParam == 0 && ! shouldDeactivateTitleBar) + wParam = TRUE; // change this and let it get passed to the DefWindowProc. - case WM_SHOWWINDOW: - if (wParam != 0) - handleBroughtToFront(); + break; - break; + case WM_MOUSEACTIVATE: + if (! component->getMouseClickGrabsKeyboardFocus()) + return MA_NOACTIVATE; - case WM_CLOSE: - if (! component->isCurrentlyBlockedByAnotherModalComponent()) - handleUserClosingWindow(); + break; - return 0; + case WM_SHOWWINDOW: + if (wParam != 0) + handleBroughtToFront(); - case WM_QUIT: - if (JUCEApplication::getInstance() != 0) - JUCEApplication::getInstance()->systemRequestedQuit(); - return 0; + break; - case WM_QUERYENDSESSION: - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->systemRequestedQuit(); - return MessageManager::getInstance()->hasStopMessageBeenSent(); - } - return TRUE; + case WM_CLOSE: + if (! component->isCurrentlyBlockedByAnotherModalComponent()) + handleUserClosingWindow(); - case WM_TRAYNOTIFY: - if (component->isCurrentlyBlockedByAnotherModalComponent()) + return 0; + + case WM_QUIT: + if (JUCEApplication::getInstance() != 0) + JUCEApplication::getInstance()->systemRequestedQuit(); + return 0; + + case WM_QUERYENDSESSION: + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + return MessageManager::getInstance()->hasStopMessageBeenSent(); + } + return TRUE; + + case WM_TRAYNOTIFY: + if (component->isCurrentlyBlockedByAnotherModalComponent()) + { + if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN + || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) { - if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN - || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) - { - Component* const current = Component::getCurrentlyModalComponent(); + Component* const current = Component::getCurrentlyModalComponent(); - if (current != 0) - current->inputAttemptWhenModal(); - } + if (current != 0) + current->inputAttemptWhenModal(); } - else - { - const int oldModifiers = currentModifiers; + } + else + { + const int oldModifiers = currentModifiers; - MouseEvent e (0, 0, ModifierKeys::getCurrentModifiersRealtime(), component, - getMouseEventTime(), 0, 0, getMouseEventTime(), 1, false); + MouseEvent e (0, 0, ModifierKeys::getCurrentModifiersRealtime(), component, + getMouseEventTime(), 0, 0, getMouseEventTime(), 1, false); - if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK) - e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::leftButtonModifier); - else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK) - e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::rightButtonModifier); + if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK) + e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::leftButtonModifier); + else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK) + e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::rightButtonModifier); - if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) - { - SetFocus (hwnd); - SetForegroundWindow (hwnd); + if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) + { + SetFocus (hwnd); + SetForegroundWindow (hwnd); - component->mouseDown (e); - } - else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) - { - e.mods = ModifierKeys (oldModifiers); - component->mouseUp (e); - } - else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) - { - e.mods = ModifierKeys (oldModifiers); - component->mouseDoubleClick (e); - } - else if (lParam == WM_MOUSEMOVE) - { - component->mouseMove (e); - } + component->mouseDown (e); } + else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) + { + e.mods = ModifierKeys (oldModifiers); + component->mouseUp (e); + } + else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) + { + e.mods = ModifierKeys (oldModifiers); + component->mouseDoubleClick (e); + } + else if (lParam == WM_MOUSEMOVE) + { + component->mouseMove (e); + } + } - break; + break; - case WM_SYNCPAINT: - return 0; + case WM_SYNCPAINT: + return 0; - case WM_PALETTECHANGED: - InvalidateRect (h, 0, 0); - break; + case WM_PALETTECHANGED: + InvalidateRect (h, 0, 0); + break; - case WM_DISPLAYCHANGE: - InvalidateRect (h, 0, 0); - createPaletteIfNeeded = true; - // intentional fall-through... - case WM_SETTINGCHANGE: // note the fall-through in the previous case! - doSettingChange(); - break; + case WM_DISPLAYCHANGE: + InvalidateRect (h, 0, 0); + createPaletteIfNeeded = true; + // intentional fall-through... + case WM_SETTINGCHANGE: // note the fall-through in the previous case! + doSettingChange(); + break; - case WM_INITMENU: - if (! hasTitleBar()) + case WM_INITMENU: + if (! hasTitleBar()) + { + if (isFullScreen()) { - if (isFullScreen()) - { - EnableMenuItem ((HMENU) wParam, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); - EnableMenuItem ((HMENU) wParam, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); - } - else if (! isMinimised()) - { - EnableMenuItem ((HMENU) wParam, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); - } + EnableMenuItem ((HMENU) wParam, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem ((HMENU) wParam, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); } - break; - - case WM_SYSCOMMAND: - switch (wParam & 0xfff0) + else if (! isMinimised()) { - case SC_CLOSE: - if (sendInputAttemptWhenModalMessage()) - return 0; + EnableMenuItem ((HMENU) wParam, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); + } + } + break; - if (hasTitleBar()) - { - PostMessage (h, WM_CLOSE, 0, 0); - return 0; - } - break; + case WM_SYSCOMMAND: + switch (wParam & 0xfff0) + { + case SC_CLOSE: + if (sendInputAttemptWhenModalMessage()) + return 0; - case SC_KEYMENU: - // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very - // obscure situations that can arise if a modal loop is started from an alt-key - // keypress). + if (hasTitleBar()) + { + PostMessage (h, WM_CLOSE, 0, 0); + return 0; + } + break; - if (hasTitleBar() && h == GetCapture()) - ReleaseCapture(); + case SC_KEYMENU: + // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very + // obscure situations that can arise if a modal loop is started from an alt-key + // keypress). - break; + if (hasTitleBar() && h == GetCapture()) + ReleaseCapture(); - case SC_MAXIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + break; - setFullScreen (true); + case SC_MAXIMIZE: + if (sendInputAttemptWhenModalMessage()) return 0; - case SC_MINIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + setFullScreen (true); + return 0; - if (! hasTitleBar()) - { - setMinimised (true); - return 0; - } - break; + case SC_MINIMIZE: + if (sendInputAttemptWhenModalMessage()) + return 0; - case SC_RESTORE: - if (sendInputAttemptWhenModalMessage()) - return 0; + if (! hasTitleBar()) + { + setMinimised (true); + return 0; + } + break; - if (hasTitleBar()) - { - if (isFullScreen()) - { - setFullScreen (false); - return 0; - } - } - else - { - if (isMinimised()) - setMinimised (false); - else if (isFullScreen()) - setFullScreen (false); + case SC_RESTORE: + if (sendInputAttemptWhenModalMessage()) + return 0; + if (hasTitleBar()) + { + if (isFullScreen()) + { + setFullScreen (false); return 0; } + } + else + { + if (isMinimised()) + setMinimised (false); + else if (isFullScreen()) + setFullScreen (false); - break; + return 0; } break; + } - case WM_NCLBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCMBUTTONDOWN: - sendInputAttemptWhenModalMessage(); - break; + break; - //case WM_IME_STARTCOMPOSITION; - // return 0; + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: + sendInputAttemptWhenModalMessage(); + break; - case WM_GETDLGCODE: - return DLGC_WANTALLKEYS; + //case WM_IME_STARTCOMPOSITION; + // return 0; - default: - break; - } + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS; + + default: + break; } } - // (the message manager lock exits before calling this, to avoid deadlocks if - // this calls into non-juce windows) return DefWindowProc (h, message, wParam, lParam); } @@ -239534,8 +239447,9 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot else { const int stride = (maxW + 7) >> 3; - uint8* const andPlane = (uint8*) juce_calloc (stride * maxH); - uint8* const xorPlane = (uint8*) juce_calloc (stride * maxH); + HeapBlock andPlane, xorPlane; + andPlane.calloc (stride * maxH); + xorPlane.calloc (stride * maxH); int index = 0; for (int y = 0; y < maxH; ++y) @@ -239556,9 +239470,6 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot } cursorH = CreateCursor (0, hotspotX, hotspotY, maxW, maxH, andPlane, xorPlane); - - juce_free (andPlane); - juce_free (xorPlane); } delete newIm; @@ -240106,7 +240017,7 @@ class FontDCHolder : private DeletedAtShutdown public: FontDCHolder() throw() - : dc (0), kps (0), numKPs (0), size (0), + : dc (0), numKPs (0), size (0), bold (false), italic (false) { } @@ -240117,7 +240028,6 @@ public: { DeleteDC (dc); DeleteObject (fontH); - juce_free (kps); } clearSingletonInstance(); @@ -240138,8 +240048,7 @@ public: { DeleteDC (dc); DeleteObject (fontH); - juce_free (kps); - kps = 0; + kps.free(); } fontH = 0; @@ -240201,7 +240110,7 @@ public: if (kps == 0) { numKPs = GetKerningPairs (dc, 0, 0); - kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs); + kps.calloc (numKPs); GetKerningPairs (dc, numKPs, kps); } @@ -240214,7 +240123,7 @@ private: HFONT fontH; HDC dc; String fontName; - KERNINGPAIR* kps; + HeapBlock kps; int numKPs, size; bool bold, italic; @@ -240277,7 +240186,7 @@ public: if (bufSize > 0) { - char* const data = (char*) juce_malloc (bufSize); + HeapBlock data (bufSize); GetGlyphOutline (dc, character, GGO_NATIVE, &gm, bufSize, data, &identityMatrix); @@ -240345,8 +240254,6 @@ public: glyphPath.closeSubPath(); } - - juce_free (data); } addGlyph (character, glyphPath, gm.gmCellIncX / height); @@ -241582,15 +241489,11 @@ static CFStringRef juceStringToCFString (const String& s) const int len = s.length(); const juce_wchar* const t = (const juce_wchar*) s; - UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); - + HeapBlock temp (len + 2); for (int i = 0; i <= len; ++i) temp[i] = t[i]; - CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); - juce_free (temp); - - return result; + return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); } static bool openMovie (QTNewMoviePropertyElement* props, int prop, Movie& movie) @@ -244840,7 +244743,7 @@ bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamples) hr = info->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4)); - byte* const buffer = (byte*) juce_malloc (bytesPerBlock); + HeapBlock buffer (bytesPerBlock); AudioSampleBuffer sourceBuffer (2, samplesPerBlock); int samplesDone = 0; @@ -244878,8 +244781,6 @@ bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamples) break; } - juce_free (buffer); - hr = info->redbook->CloseAudioTrack(); delete source; @@ -245553,7 +245454,6 @@ public: optionalDllForDirectLoading (optionalDllForDirectLoading_), currentBitDepth (16), currentSampleRate (0), - tempBuffer (0), isOpen_ (false), isStarted (false), postOutput (true), @@ -245580,8 +245480,6 @@ public: close(); log ("ASIO - exiting"); removeCurrentDriver(); - - juce_free (tempBuffer); } void updateSampleRates() @@ -245916,9 +245814,7 @@ public: { buffersCreated = true; - juce_free (tempBuffer); - - tempBuffer = (float*) juce_calloc (totalBuffers * currentBlockSizeSamples * sizeof (float) + 128); + tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32); int n = 0; Array types; @@ -246304,7 +246200,7 @@ private: bool outputChannelLittleEndian [maxASIOChannels]; WaitableEvent event1; - float* tempBuffer; + HeapBlock tempBuffer; int volatile bufferIndex, numActiveInputChans, numActiveOutputChans; bool isOpen_, isStarted; @@ -248561,8 +248457,7 @@ private: int64 volatile lastBlockTime; double sampleRate; BitArray enabledInputs, enabledOutputs; - float** inputBuffers; - float** outputBuffers; + HeapBlock inputBuffers, outputBuffers; AudioIODeviceCallback* callback; CriticalSection startStopLock; @@ -248587,15 +248482,13 @@ private: for (i = 0; i < numInputBuffers; ++i) juce_free (inputBuffers[i]); - delete[] inputBuffers; - inputBuffers = 0; + inputBuffers.free(); numInputBuffers = 0; for (i = 0; i < numOutputBuffers; ++i) juce_free (outputBuffers[i]); - delete[] outputBuffers; - outputBuffers = 0; + outputBuffers.free(); numOutputBuffers = 0; } @@ -248909,8 +248802,7 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels, false); numInputBuffers = enabledInputs.countNumberOfSetBits(); - inputBuffers = new float* [numInputBuffers + 2]; - zeromem (inputBuffers, sizeof (float*) * numInputBuffers + 2); + inputBuffers.calloc (numInputBuffers + 2); int i, numIns = 0; for (i = 0; i <= enabledInputs.getHighestBit(); i += 2) @@ -248937,8 +248829,7 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels, false); numOutputBuffers = enabledOutputs.countNumberOfSetBits(); - outputBuffers = new float* [numOutputBuffers + 2]; - zeromem (outputBuffers, sizeof (float*) * numOutputBuffers + 2); + outputBuffers.calloc (numOutputBuffers + 2); int numOuts = 0; for (i = 0; i <= enabledOutputs.getHighestBit(); i += 2) @@ -250253,14 +250144,14 @@ public: if (getPin (filter, PINDIR_OUTPUT, &pin)) { ComSmartPtr pushSource; - hr = pin->QueryInterface (IID_IAMPushSource, (void**) &pushSource); + HRESULT hr = pin->QueryInterface (IID_IAMPushSource, (void**) &pushSource); if (pushSource != 0) { REFERENCE_TIME latency = 0; - hr = ps->GetLatency (&latency); + hr = pushSource->GetLatency (&latency); - firstRecordedTime -= RelativeTime ((double) latency); + firstRecordedTime = firstRecordedTime - RelativeTime ((double) latency); } } } @@ -254240,7 +254131,7 @@ static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& i { const int width = image.getWidth(); const int height = image.getHeight(); - uint32* const colour = (uint32*) juce_malloc (width * height * sizeof (uint32)); + HeapBlock colour (width * height); int index = 0; for (int y = 0; y < height; ++y) @@ -254256,7 +254147,6 @@ static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& i GC gc = XCreateGC (display, pixmap, 0, 0); XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); XFreeGC (display, gc); - juce_free (colour); return pixmap; } @@ -254266,7 +254156,8 @@ static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& ima const int width = image.getWidth(); const int height = image.getHeight(); const int stride = (width + 7) >> 3; - uint8* const mask = (uint8*) juce_calloc (stride * height); + HeapBlock mask; + mask.calloc (stride * height); const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); for (int y = 0; y < height; ++y) @@ -254281,12 +254172,8 @@ static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& ima } } - Pixmap pixmap = XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), - (char*) mask, width, height, 1, 0, 1); - - juce_free (mask); - - return pixmap; + return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), + (char*) mask, width, height, 1, 0, 1); } class XBitmapImage : public Image @@ -254352,7 +254239,8 @@ public: if (! usingXShm) #endif { - imageData = (uint8*) juce_malloc (lineStride * h); + imageDataAllocated.malloc (lineStride * h); + imageData = imageDataAllocated; if (format_ == ARGB && clearImage) zeromem (imageData, h * lineStride); @@ -254380,7 +254268,8 @@ public: const int pixelStride = 2; const int lineStride = ((w * pixelStride + 3) & ~3); - xImage->data = (char*) juce_malloc (lineStride * h); + imageData16Bit.malloc (lineStride * h); + xImage->data = imageData16Bit; xImage->bitmap_pad = 16; xImage->depth = pixelStride * 8; xImage->bytes_per_line = lineStride; @@ -254413,13 +254302,9 @@ public: else #endif { - juce_free (xImage->data); xImage->data = 0; XDestroyImage (xImage); } - - if (! is16Bit) - imageData = 0; // to stop the base class freeing this (for the 16-bit version we want it to free it) } void blitToWindow (Window window, int dx, int dy, int dw, int dh, int sx, int sy) @@ -254474,6 +254359,7 @@ public: private: XImage* xImage; const bool is16Bit; + HeapBlock imageData16Bit; #if JUCE_USE_XSHM XShmSegmentInfo segmentInfo; @@ -254937,7 +254823,7 @@ public: void setIcon (const Image& newIcon) { const int dataSize = newIcon.getWidth() * newIcon.getHeight() + 2; - unsigned long* const data = (unsigned long*) juce_malloc (dataSize * sizeof (uint32)); + HeapBlock data (dataSize); int index = 0; data[index++] = newIcon.getWidth(); @@ -254952,8 +254838,6 @@ public: XA_CARDINAL, 32, PropModeReplace, (unsigned char*) data, dataSize); - juce_free (data); - deleteIconPixmaps(); XWMHints* wmHints = XGetWMHints (display, windowH); @@ -256568,8 +256452,9 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot } const int stride = (cursorW + 7) >> 3; - uint8* const maskPlane = (uint8*) juce_calloc (stride * cursorH); - uint8* const sourcePlane = (uint8*) juce_calloc (stride * cursorH); + HeapBlock maskPlane, sourcePlane; + maskPlane.calloc (stride * cursorH); + sourcePlane.calloc (stride * cursorH); const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); @@ -256593,9 +256478,6 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot Pixmap sourcePixmap = XCreatePixmapFromBitmapData (display, root, (char*) sourcePlane, cursorW, cursorH, 0xffff, 0, 1); Pixmap maskPixmap = XCreatePixmapFromBitmapData (display, root, (char*) maskPlane, cursorW, cursorH, 0xffff, 0, 1); - juce_free (maskPlane); - juce_free (sourcePlane); - XColor white, black; black.red = black.green = black.blue = 0; white.red = white.green = white.blue = 0xffff; @@ -258201,8 +258083,6 @@ public: outputId (outputId_), isOpen_ (false), callback (0), - inChans (0), - outChans (0), totalNumberOfInputChannels (0), totalNumberOfOutputChannels (0) { @@ -258241,8 +258121,8 @@ public: JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)); } - inChans = (float**) juce_calloc (sizeof (float*) * (totalNumberOfInputChannels + 2)); - outChans = (float**) juce_calloc (sizeof (float*) * (totalNumberOfOutputChannels + 2)); + inChans.calloc (totalNumberOfInputChannels + 2); + outChans.calloc (totalNumberOfOutputChannels + 2); } } @@ -258254,9 +258134,6 @@ public: JUCE_NAMESPACE::jack_client_close (client); client = 0; } - - juce_free (inChans); - juce_free (outChans); } const StringArray getChannelNames (bool forInput) const @@ -258521,8 +258398,7 @@ private: AudioIODeviceCallback* callback; CriticalSection callbackLock; - float** inChans; - float** outChans; + HeapBlock inChans, outChans; int totalNumberOfInputChannels; int totalNumberOfOutputChannels; VoidArray inputPorts, outputPorts; @@ -258961,7 +258837,7 @@ public: if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) { - uint8* const buffer = (uint8*) juce_malloc (maxEventSize); + HeapBlock buffer (maxEventSize); const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); @@ -259004,7 +258880,6 @@ public: } snd_midi_event_free (midiParser); - juce_free (buffer); } }; @@ -259390,20 +259265,15 @@ const String PlatformUtilities::cfStringToJuceString (CFStringRef cfString) { #if JUCE_STRINGS_ARE_UNICODE CFRange range = { 0, CFStringGetLength (cfString) }; - UniChar* const u = (UniChar*) juce_malloc (sizeof (UniChar) * (range.length + 1)); - + HeapBlock u (range.length + 1); CFStringGetCharacters (cfString, range, u); u[range.length] = 0; - result = convertUTF16ToString (u); - - juce_free (u); #else const int len = CFStringGetLength (cfString); - char* buffer = (char*) juce_malloc (len + 1); + HeapBlock buffer (len + 1); CFStringGetCString (cfString, buffer, len + 1, CFStringGetSystemEncoding()); result = buffer; - juce_free (buffer); #endif } @@ -259415,16 +259285,12 @@ CFStringRef PlatformUtilities::juceStringToCFString (const String& s) #if JUCE_STRINGS_ARE_UNICODE const int len = s.length(); const juce_wchar* t = (const juce_wchar*) s; - - UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); + HeapBlock temp (len + 2); for (int i = 0; i <= len; ++i) temp[i] = t[i]; - CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); - juce_free (temp); - - return result; + return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); #else return CFStringCreateWithCString (kCFAllocatorDefault, @@ -259458,8 +259324,9 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) { const int len = s.length(); - UniChar* const tempIn = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4); - UniChar* const tempOut = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4); + HeapBlock tempIn, tempOut; + tempIn.calloc (len + 2); + tempOut.calloc (len + 2); for (int i = 0; i <= len; ++i) tempIn[i] = s[i]; @@ -259485,9 +259352,6 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) t[i] = 0; } - juce_free (tempIn); - juce_free (tempOut); - DisposeUnicodeToTextInfo (&conversionInfo); } @@ -262078,45 +261942,38 @@ public: return 0; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); float x = 0; #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) for (int i = 0; i < length; ++i) x += advances[i]; - - juce_free (advances); } #endif - juce_free (glyphs); - return x * unitsToHeightScaleFactor; } @@ -262128,10 +261985,11 @@ public: return; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; int x = 0; @@ -262142,12 +262000,11 @@ public: resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; float x = 0; @@ -262157,13 +262014,11 @@ public: xOffsets.add (x * unitsToHeightScaleFactor); resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) { @@ -262175,12 +262030,8 @@ public: resultGlyphs.add (glyphs[i]); } } - - juce_free (advances); } #endif - - juce_free (glyphs); } bool getOutlineForGlyph (int glyphNumber, Path& path) @@ -262245,19 +262096,20 @@ private: AffineTransform pathTransform; #endif - CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw() + void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) throw() { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) #endif { - NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length); + glyphs.malloc (sizeof (NSGlyph) * length, 1); + NSGlyph* const g = (NSGlyph*) glyphs; for (int i = 0; i < length; ++i) g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; - return (CGGlyph*) g; + return; } #endif @@ -262265,12 +262117,10 @@ private: if (charToGlyphMapper == 0) charToGlyphMapper = new CharToGlyphMapper (fontRef); - CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length); + glyphs.malloc (length); for (int i = 0; i < length; ++i) - g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); - - return g; + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); #endif } @@ -262522,7 +262372,6 @@ public: CoreGraphicsContext (CGContextRef context_, const float flipHeight_) : context (context_), flipHeight (flipHeight_), - gradientLookupTable (0), numGradientLookupEntries (0) { CGContextRetain (context); @@ -262545,7 +262394,6 @@ public: CGColorSpaceRelease (rgbColourSpace); CGColorSpaceRelease (greyColourSpace); delete state; - delete gradientLookupTable; } bool isVectorDevice() const { return false; } @@ -262572,7 +262420,7 @@ public: { const int numRects = clipRegion.getNumRectangles(); - CGRect* const rects = new CGRect [numRects]; + HeapBlock rects (numRects); for (int i = 0; i < numRects; ++i) { const Rectangle& r = clipRegion.getRectangle(i); @@ -262580,8 +262428,6 @@ public: } CGContextClipToRects (context, rects, numRects); - delete[] rects; - return ! isClipEmpty(); } } @@ -262950,7 +262796,7 @@ private: SavedState* state; OwnedArray stateStack; - PixelARGB* gradientLookupTable; + HeapBlock gradientLookupTable; int numGradientLookupEntries; static void gradientCallback (void* info, const CGFloat* inData, CGFloat* outData) @@ -262969,8 +262815,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { - delete gradientLookupTable; - gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); --numGradientLookupEntries; CGShadingRef result = 0; @@ -265992,7 +265837,8 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) const int maxPacketSize = 256; int pos = 0, bytesLeft = message.getRawDataSize(); const int numPackets = (bytesLeft + maxPacketSize - 1) / maxPacketSize; - MIDIPacketList* const packets = (MIDIPacketList*) juce_malloc (32 * numPackets + message.getRawDataSize()); + HeapBlock packets; + packets.malloc (32 * numPackets + message.getRawDataSize(), 1); packets->numPackets = numPackets; MIDIPacket* p = packets->packet; @@ -266011,8 +265857,6 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) MIDISend (mpe->port, mpe->endPoint, packets); else MIDIReceived (mpe->endPoint, packets); - - juce_free (packets); } else { @@ -266546,45 +266390,38 @@ public: return 0; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); float x = 0; #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) for (int i = 0; i < length; ++i) x += advances[i]; - - juce_free (advances); } #endif - juce_free (glyphs); - return x * unitsToHeightScaleFactor; } @@ -266596,10 +266433,11 @@ public: return; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; int x = 0; @@ -266610,12 +266448,11 @@ public: resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; float x = 0; @@ -266625,13 +266462,11 @@ public: xOffsets.add (x * unitsToHeightScaleFactor); resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) { @@ -266643,12 +266478,8 @@ public: resultGlyphs.add (glyphs[i]); } } - - juce_free (advances); } #endif - - juce_free (glyphs); } bool getOutlineForGlyph (int glyphNumber, Path& path) @@ -266713,19 +266544,20 @@ private: AffineTransform pathTransform; #endif - CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw() + void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) throw() { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) #endif { - NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length); + glyphs.malloc (sizeof (NSGlyph) * length, 1); + NSGlyph* const g = (NSGlyph*) glyphs; for (int i = 0; i < length; ++i) g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; - return (CGGlyph*) g; + return; } #endif @@ -266733,12 +266565,10 @@ private: if (charToGlyphMapper == 0) charToGlyphMapper = new CharToGlyphMapper (fontRef); - CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length); + glyphs.malloc (length); for (int i = 0; i < length; ++i) - g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); - - return g; + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); #endif } @@ -266992,7 +266822,6 @@ public: CoreGraphicsContext (CGContextRef context_, const float flipHeight_) : context (context_), flipHeight (flipHeight_), - gradientLookupTable (0), numGradientLookupEntries (0) { CGContextRetain (context); @@ -267015,7 +266844,6 @@ public: CGColorSpaceRelease (rgbColourSpace); CGColorSpaceRelease (greyColourSpace); delete state; - delete gradientLookupTable; } bool isVectorDevice() const { return false; } @@ -267042,7 +266870,7 @@ public: { const int numRects = clipRegion.getNumRectangles(); - CGRect* const rects = new CGRect [numRects]; + HeapBlock rects (numRects); for (int i = 0; i < numRects; ++i) { const Rectangle& r = clipRegion.getRectangle(i); @@ -267050,8 +266878,6 @@ public: } CGContextClipToRects (context, rects, numRects); - delete[] rects; - return ! isClipEmpty(); } } @@ -267420,7 +267246,7 @@ private: SavedState* state; OwnedArray stateStack; - PixelARGB* gradientLookupTable; + HeapBlock gradientLookupTable; int numGradientLookupEntries; static void gradientCallback (void* info, const CGFloat* inData, CGFloat* outData) @@ -267439,8 +267265,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { - delete gradientLookupTable; - gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); --numGradientLookupEntries; CGShadingRef result = 0; @@ -272140,16 +271965,11 @@ public: started (false), sampleRate (0), bufferSize (512), - audioBuffer (0), numInputChans (0), numOutputChans (0), callbacksAllowed (true), numInputChannelInfos (0), - numOutputChannelInfos (0), - tempInputBuffers (0), - tempOutputBuffers (0), - inputChannelInfo (0), - outputChannelInfo (0) + numOutputChannelInfos (0) { jassert (deviceID != 0); @@ -272174,24 +271994,15 @@ public: stop (false); delete inputDevice; - - juce_free (audioBuffer); - juce_free (tempInputBuffers); - juce_free (tempOutputBuffers); - juce_free (inputChannelInfo); - juce_free (outputChannelInfo); } void allocateTempBuffers() { const int tempBufSize = bufferSize + 4; - juce_free (audioBuffer); - audioBuffer = (float*) juce_calloc ((numInputChans + numOutputChans) * tempBufSize * sizeof (float)); + audioBuffer.calloc ((numInputChans + numOutputChans) * tempBufSize); - juce_free (tempInputBuffers); - tempInputBuffers = (float**) juce_calloc (sizeof (float*) * (numInputChans + 2)); - juce_free (tempOutputBuffers); - tempOutputBuffers = (float**) juce_calloc (sizeof (float*) * (numOutputChans + 2)); + tempInputBuffers.calloc (numInputChans + 2); + tempOutputBuffers.calloc (numOutputChans + 2); int i, count = 0; for (i = 0; i < numInputChans; ++i) @@ -272214,7 +272025,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioBufferList* const bufList = (AudioBufferList*) juce_calloc (size); + HeapBlock bufList; + bufList.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) { @@ -272274,8 +272086,6 @@ public: } } } - - juce_free (bufList); } } @@ -272315,7 +272125,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioValueRange* ranges = (AudioValueRange*) juce_calloc (size); + HeapBlock ranges; + ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) { @@ -272336,8 +272147,6 @@ public: if (bufferSize > 0) bufferSizes.addIfNotAlreadyThere (bufferSize); } - - juce_free (ranges); } if (bufferSizes.size() == 0 && bufferSize > 0) @@ -272351,7 +272160,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioValueRange* ranges = (AudioValueRange*) juce_calloc (size); + HeapBlock ranges; + ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) { @@ -272370,8 +272180,6 @@ public: } } } - - juce_free (ranges); } if (sampleRates.size() == 0 && sampleRate > 0) @@ -272403,12 +272211,10 @@ public: inChanNames.clear(); outChanNames.clear(); - juce_free (inputChannelInfo); - inputChannelInfo = (CallbackDetailsForChannel*) juce_calloc (sizeof (CallbackDetailsForChannel) * (numInputChans + 2)); + inputChannelInfo.calloc (numInputChans + 2); numInputChannelInfos = 0; - juce_free (outputChannelInfo); - outputChannelInfo = (CallbackDetailsForChannel*) juce_calloc (sizeof (CallbackDetailsForChannel) * (numOutputChans + 2)); + outputChannelInfo.calloc (numOutputChans + 2); numOutputChannelInfos = 0; fillInChannelInfo (true); @@ -272418,36 +272224,31 @@ public: const StringArray getSources (bool input) { StringArray s; - int num = 0; - OSType* types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + for (int i = 0; i < num; ++i) { - for (int i = 0; i < num; ++i) - { - AudioValueTranslation avt; - char buffer[256]; + AudioValueTranslation avt; + char buffer[256]; - avt.mInputData = (void*) &(types[i]); - avt.mInputDataSize = sizeof (UInt32); - avt.mOutputData = buffer; - avt.mOutputDataSize = 256; + avt.mInputData = (void*) &(types[i]); + avt.mInputDataSize = sizeof (UInt32); + avt.mOutputData = buffer; + avt.mOutputDataSize = 256; - UInt32 transSize = sizeof (avt); + UInt32 transSize = sizeof (avt); - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyDataSourceNameForID; - pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; - pa.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress pa; + pa.mSelector = kAudioDevicePropertyDataSourceNameForID; + pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + pa.mElement = kAudioObjectPropertyElementMaster; - if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &transSize, &avt))) - { - DBG (buffer); - s.add (buffer); - } + if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &transSize, &avt))) + { + DBG (buffer); + s.add (buffer); } - - juce_free (types); } return s; @@ -272468,21 +272269,16 @@ public: { if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ¤tSourceID))) { - int num = 0; - OSType* const types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + for (int i = 0; i < num; ++i) { - for (int i = 0; i < num; ++i) + if (types[num] == currentSourceID) { - if (types[num] == currentSourceID) - { - result = i; - break; - } + result = i; + break; } - - juce_free (types); } } } @@ -272494,24 +272290,19 @@ public: { if (deviceID != 0) { - int num = 0; - OSType* types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + if (((unsigned int) index) < (unsigned int) num) { - if (((unsigned int) index) < (unsigned int) num) - { - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyDataSource; - pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; - pa.mElement = kAudioObjectPropertyElementMaster; - - OSType typeId = types[index]; + AudioObjectPropertyAddress pa; + pa.mSelector = kAudioDevicePropertyDataSource; + pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + pa.mElement = kAudioObjectPropertyElementMaster; - OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (typeId), &typeId)); - } + OSType typeId = types[index]; - juce_free (types); + OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (typeId), &typeId)); } } } @@ -272825,7 +272616,8 @@ public: && AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr && size > 0) { - AudioDeviceID* devs = (AudioDeviceID*) juce_calloc (size); + HeapBlock devs; + devs.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, devs))) { @@ -272847,8 +272639,6 @@ public: } } } - - juce_free (devs); } return result; @@ -272875,7 +272665,7 @@ private: bool started; double sampleRate; int bufferSize; - float* audioBuffer; + HeapBlock audioBuffer; int numInputChans, numOutputChans; bool callbacksAllowed; @@ -272887,10 +272677,8 @@ private: }; int numInputChannelInfos, numOutputChannelInfos; - CallbackDetailsForChannel* inputChannelInfo; - CallbackDetailsForChannel* outputChannelInfo; - float** tempInputBuffers; - float** tempOutputBuffers; + HeapBlock inputChannelInfo, outputChannelInfo; + HeapBlock tempInputBuffers, tempOutputBuffers; CoreAudioInternal (const CoreAudioInternal&); const CoreAudioInternal& operator= (const CoreAudioInternal&); @@ -272933,34 +272721,24 @@ private: return noErr; } - static OSType* getAllDataSourcesForDevice (AudioDeviceID deviceID, const bool input, int& num) + static int getAllDataSourcesForDevice (AudioDeviceID deviceID, const bool input, HeapBlock & types) { - OSType* types = 0; - UInt32 size = 0; - num = 0; - AudioObjectPropertyAddress pa; pa.mSelector = kAudioDevicePropertyDataSources; pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = kAudioObjectPropertyElementMaster; + UInt32 size = 0; if (deviceID != 0 && OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - types = (OSType*) juce_calloc (size); + types.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types))) - { - num = size / sizeof (OSType); - } - else - { - juce_free (types); - types = 0; - } + return size / sizeof (OSType); } - return types; + return 0; } }; @@ -273247,7 +273025,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size))) { - AudioDeviceID* const devs = (AudioDeviceID*) juce_calloc (size); + HeapBlock devs; + devs.calloc (size, 1); if (OK (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs))) { @@ -273285,8 +273064,6 @@ public: alreadyLogged = true; } - - juce_free (devs); } inputDeviceNames.appendNumbersToDuplicates (false, true); @@ -273393,7 +273170,8 @@ private: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioBufferList* const bufList = (AudioBufferList*) juce_calloc (size); + HeapBlock bufList; + bufList.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) { @@ -273405,8 +273183,6 @@ private: total += b.mNumberChannels; } } - - juce_free (bufList); } return total; @@ -273734,7 +273510,8 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) const int maxPacketSize = 256; int pos = 0, bytesLeft = message.getRawDataSize(); const int numPackets = (bytesLeft + maxPacketSize - 1) / maxPacketSize; - MIDIPacketList* const packets = (MIDIPacketList*) juce_malloc (32 * numPackets + message.getRawDataSize()); + HeapBlock packets; + packets.malloc (32 * numPackets + message.getRawDataSize(), 1); packets->numPackets = numPackets; MIDIPacket* p = packets->packet; @@ -273753,8 +273530,6 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) MIDISend (mpe->port, mpe->endPoint, packets); else MIDIReceived (mpe->endPoint, packets); - - juce_free (packets); } else { diff --git a/juce_amalgamated.h b/juce_amalgamated.h index a371ef64f5..7f88500e21 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -763,13 +763,24 @@ extern bool JUCE_API JUCE_CALLTYPE juce_isRunningUnderDebugger() throw(); // Win32 debug non-DLL versions.. - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) _malloc_dbg (numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) _calloc_dbg (1, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) _realloc_dbg (location, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) _free_dbg (location, _NORMAL_BLOCK) #else @@ -783,13 +794,24 @@ extern bool JUCE_API JUCE_CALLTYPE juce_isRunningUnderDebugger() throw(); extern JUCE_API void* juce_DebugRealloc (void* const block, const int size, const char* file, const int line); extern JUCE_API void juce_DebugFree (void* const block); - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_DebugMalloc (numBytes, __FILE__, __LINE__) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_DebugCalloc (numBytes, __FILE__, __LINE__) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_DebugRealloc (location, numBytes, __FILE__, __LINE__) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) JUCE_NAMESPACE::juce_DebugFree (location) #endif @@ -815,13 +837,24 @@ extern bool JUCE_API JUCE_CALLTYPE juce_isRunningUnderDebugger() throw(); extern JUCE_API void* juce_Realloc (void* const block, const int size); extern JUCE_API void juce_Free (void* const block); - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_Malloc (numBytes) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_Calloc (numBytes) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_Realloc (location, numBytes) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) JUCE_NAMESPACE::juce_Free (location) #define juce_UseDebuggingNewOperator \ @@ -833,13 +866,24 @@ extern bool JUCE_API JUCE_CALLTYPE juce_isRunningUnderDebugger() throw(); // Mac, Linux and Win32 (release) versions.. - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) malloc (numBytes) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) calloc (1, numBytes) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) realloc (location, numBytes) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) free (location) #endif @@ -2607,210 +2651,11 @@ BEGIN_JUCE_NAMESPACE #ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ #define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ -#ifndef __JUCE_ATOMIC_JUCEHEADER__ - -/********* Start of inlined file: juce_Atomic.h *********/ -#ifndef __JUCE_ATOMIC_JUCEHEADER__ -#define __JUCE_ATOMIC_JUCEHEADER__ - -// Atomic increment/decrement operations.. - -#if (JUCE_MAC || JUCE_IPHONE) && ! DOXYGEN - - #include - static forcedinline void atomicIncrement (int& variable) throw() { OSAtomicIncrement32 ((int32_t*) &variable); } - static forcedinline int atomicIncrementAndReturn (int& variable) throw() { return OSAtomicIncrement32 ((int32_t*) &variable); } - static forcedinline void atomicDecrement (int& variable) throw() { OSAtomicDecrement32 ((int32_t*) &variable); } - static forcedinline int atomicDecrementAndReturn (int& variable) throw() { return OSAtomicDecrement32 ((int32_t*) &variable); } - -#elif JUCE_GCC - - #if JUCE_USE_GCC_ATOMIC_INTRINSICS - forcedinline void atomicIncrement (int& variable) throw() { __sync_add_and_fetch (&variable, 1); } - forcedinline int atomicIncrementAndReturn (int& variable) throw() { return __sync_add_and_fetch (&variable, 1); } - forcedinline void atomicDecrement (int& variable) throw() { __sync_add_and_fetch (&variable, -1); } - forcedinline int atomicDecrementAndReturn (int& variable) throw() { return __sync_add_and_fetch (&variable, -1); } - #else - - /** Increments an integer in a thread-safe way. */ - forcedinline void atomicIncrement (int& variable) throw() - { - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock incl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock incl %0" - : "=m" (variable) - : "m" (variable)); - #endif - } - - /** Increments an integer in a thread-safe way and returns the incremented value. */ - forcedinline int atomicIncrementAndReturn (int& variable) throw() - { - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - incl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - incl %%eax" - : "=a" (result) - : "c" (&variable), "a" (1) - : "memory"); - #endif - - return result; - } - - /** Decrememts an integer in a thread-safe way. */ - forcedinline void atomicDecrement (int& variable) throw() - { - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock decl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock decl %0" - : "=m" (variable) - : "m" (variable)); - #endif - } - - /** Decrememts an integer in a thread-safe way and returns the incremented value. */ - forcedinline int atomicDecrementAndReturn (int& variable) throw() - { - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - decl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (-1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - decl %%eax" - : "=a" (result) - : "c" (&variable), "a" (-1) - : "memory"); - #endif - return result; - } - #endif - -#elif JUCE_USE_INTRINSICS - - #pragma intrinsic (_InterlockedIncrement) - #pragma intrinsic (_InterlockedDecrement) - - /** Increments an integer in a thread-safe way. */ - forcedinline void __fastcall atomicIncrement (int& variable) throw() - { - _InterlockedIncrement (reinterpret_cast (&variable)); - } - - /** Increments an integer in a thread-safe way and returns the incremented value. */ - forcedinline int __fastcall atomicIncrementAndReturn (int& variable) throw() - { - return _InterlockedIncrement (reinterpret_cast (&variable)); - } - - /** Decrememts an integer in a thread-safe way. */ - forcedinline void __fastcall atomicDecrement (int& variable) throw() - { - _InterlockedDecrement (reinterpret_cast (&variable)); - } - - /** Decrememts an integer in a thread-safe way and returns the incremented value. */ - forcedinline int __fastcall atomicDecrementAndReturn (int& variable) throw() - { - return _InterlockedDecrement (reinterpret_cast (&variable)); - } -#else - - /** Increments an integer in a thread-safe way. */ - forcedinline void __fastcall atomicIncrement (int& variable) throw() - { - __asm { - mov ecx, dword ptr [variable] - lock inc dword ptr [ecx] - } - } - - /** Increments an integer in a thread-safe way and returns the incremented value. */ - forcedinline int __fastcall atomicIncrementAndReturn (int& variable) throw() - { - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, 1 - lock xadd dword ptr [ecx], eax - inc eax - mov result, eax - } - - return result; - } - - /** Decrememts an integer in a thread-safe way. */ - forcedinline void __fastcall atomicDecrement (int& variable) throw() - { - __asm { - mov ecx, dword ptr [variable] - lock dec dword ptr [ecx] - } - } - - /** Decrememts an integer in a thread-safe way and returns the incremented value. */ - forcedinline int __fastcall atomicDecrementAndReturn (int& variable) throw() - { - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, -1 - lock xadd dword ptr [ecx], eax - dec eax - mov result, eax - } - - return result; - } -#endif - -#endif // __JUCE_ATOMIC_JUCEHEADER__ -/********* End of inlined file: juce_Atomic.h *********/ - -#endif -#ifndef __JUCE_DATACONVERSIONS_JUCEHEADER__ - -#endif -#ifndef __JUCE_FILELOGGER_JUCEHEADER__ - -/********* Start of inlined file: juce_FileLogger.h *********/ -#ifndef __JUCE_FILELOGGER_JUCEHEADER__ -#define __JUCE_FILELOGGER_JUCEHEADER__ - -/********* Start of inlined file: juce_File.h *********/ -#ifndef __JUCE_FILE_JUCEHEADER__ -#define __JUCE_FILE_JUCEHEADER__ +#ifndef __JUCE_ARRAY_JUCEHEADER__ -/********* Start of inlined file: juce_OwnedArray.h *********/ -#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ -#define __JUCE_OWNEDARRAY_JUCEHEADER__ +/********* Start of inlined file: juce_Array.h *********/ +#ifndef __JUCE_ARRAY_JUCEHEADER__ +#define __JUCE_ARRAY_JUCEHEADER__ /********* Start of inlined file: juce_ArrayAllocationBase.h *********/ #ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ @@ -3310,28 +3155,27 @@ public: #endif // __JUCE_CRITICALSECTION_JUCEHEADER__ /********* End of inlined file: juce_CriticalSection.h *********/ -/** An array designed for holding objects. +/** + Holds a list of primitive objects, such as ints, doubles, or pointers. - This holds a list of pointers to objects, and will automatically - delete the objects when they are removed from the array, or when the - array is itself deleted. + Examples of arrays are: Array or Array - Declare it in the form: OwnedArray + Note that when holding pointers to objects, the array doesn't take any ownership + of the objects - for doing this, see the OwnedArray class or the ReferenceCountedArray class. - ..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass()); + If you're using a class or struct as the element type, it must be + capable of being copied or moved with a straightforward memcpy, rather than + needing construction and destruction code. - After adding objects, they are 'owned' by the array and will be deleted when - removed or replaced. + For holding lists of strings, use the specialised class StringArray. To make all the array's methods thread-safe, pass in "CriticalSection" as the templated TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. - @see Array, ReferenceCountedArray, StringArray, CriticalSection + @see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection */ -template - -class OwnedArray +template +class Array { public: @@ -3341,124 +3185,255 @@ public: used by the array will grow. Only change it from the default if you know the array is going to be very big and needs to be able to grow efficiently. */ - OwnedArray (const int granularity = juceDefaultArrayGranularity) throw() - : data (granularity), - numUsed (0) + Array (const int granularity = juceDefaultArrayGranularity) throw() + : data (granularity), + numUsed (0) { } - /** Deletes the array and also deletes any objects inside it. + /** Creates a copy of another array. + @param other the array to copy + */ + Array (const Array& other) throw() + : data (other.data.granularity) + { + other.lockArray(); + numUsed = other.numUsed; + data.setAllocatedSize (other.numUsed); + memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); + other.unlockArray(); + } - To get rid of the array without deleting its objects, use its - clear (false) method before deleting it. + /** Initalises from a null-terminated C array of values. + + @param values the array to copy from */ - ~OwnedArray() + Array (const ElementType* values) throw() + : data (juceDefaultArrayGranularity), + numUsed (0) { - clear (true); + while (*values != 0) + add (*values++); } - /** Clears the array, optionally deleting the objects inside it first. */ - void clear (const bool deleteObjects = true) + /** Initalises from a C array of values. + + @param values the array to copy from + @param numValues the number of values in the array + */ + Array (const ElementType* values, int numValues) throw() + : data (juceDefaultArrayGranularity), + numUsed (numValues) + { + data.setAllocatedSize (numValues); + memcpy (data.elements, values, numValues * sizeof (ElementType)); + } + + /** Destructor. */ + ~Array() throw() + { + } + + /** Copies another array. + @param other the array to copy + */ + const Array & operator= (const Array & other) throw() + { + if (this != &other) + { + other.lockArray(); + lock.enter(); + + data.granularity = other.data.granularity; + data.ensureAllocatedSize (other.size()); + numUsed = other.numUsed; + memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); + minimiseStorageOverheads(); + + lock.exit(); + other.unlockArray(); + } + + return *this; + } + + /** Compares this array to another one. + Two arrays are considered equal if they both contain the same set of + elements, in the same order. + @param other the other array to compare with + */ + template + bool operator== (const OtherArrayType& other) const throw() { lock.enter(); - if (deleteObjects) + if (numUsed != other.numUsed) { - while (numUsed > 0) - delete data.elements [--numUsed]; + lock.exit(); + return false; + } + + for (int i = numUsed; --i >= 0;) + { + if (data.elements [i] != other.data.elements [i]) + { + lock.exit(); + return false; + } } + lock.exit(); + return true; + } + + /** Compares this array to another one. + Two arrays are considered equal if they both contain the same set of + elements, in the same order. + @param other the other array to compare with + */ + template + bool operator!= (const OtherArrayType& other) const throw() + { + return ! operator== (other); + } + + /** Removes all elements from the array. + This will remove all the elements, and free any storage that the array is + using. To clear the array without freeing the storage, use the clearQuick() + method instead. + + @see clearQuick + */ + void clear() throw() + { + lock.enter(); data.setAllocatedSize (0); numUsed = 0; lock.exit(); } - /** Returns the number of items currently in the array. - @see operator[] + /** Removes all elements from the array without freeing the array's allocated storage. + + @see clear + */ + void clearQuick() throw() + { + lock.enter(); + numUsed = 0; + lock.exit(); + } + + /** Returns the current number of elements in the array. */ inline int size() const throw() { return numUsed; } - /** Returns a pointer to the object at this index in the array. + /** Returns one of the elements in the array. + If the index passed in is beyond the range of valid elements, this + will return zero. - If the index is out-of-range, this will return a null pointer, (and - it could be null anyway, because it's ok for the array to hold null - pointers as well as objects). + If you're certain that the index will always be a valid element, you + can call getUnchecked() instead, which is faster. - @see getUnchecked + @param index the index of the element being requested (0 is the first element in the array) + @see getUnchecked, getFirst, getLast */ - inline ObjectClass* operator[] (const int index) const throw() + inline ElementType operator[] (const int index) const throw() { lock.enter(); - ObjectClass* const result = (((unsigned int) index) < (unsigned int) numUsed) - ? data.elements [index] - : (ObjectClass*) 0; + const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) + ? data.elements [index] + : ElementType(); lock.exit(); return result; } - /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. + /** Returns one of the elements in the array, without checking the index passed in. - This is a faster and less safe version of operator[] which doesn't check the index passed in, so - it can be used when you're sure the index if always going to be legal. + Unlike the operator[] method, this will try to return an element without + checking that the index is within the bounds of the array, so should only + be used when you're confident that it will always be a valid index. + + @param index the index of the element being requested (0 is the first element in the array) + @see operator[], getFirst, getLast */ - inline ObjectClass* getUnchecked (const int index) const throw() + inline ElementType getUnchecked (const int index) const throw() { lock.enter(); jassert (((unsigned int) index) < (unsigned int) numUsed); - ObjectClass* const result = data.elements [index]; + const ElementType result = data.elements [index]; lock.exit(); return result; } - /** Returns a pointer to the first object in the array. + /** Returns a direct reference to one of the elements in the array, without checking the index passed in. - This will return a null pointer if the array's empty. - @see getLast + This is like getUnchecked, but returns a direct reference to the element, so that + you can alter it directly. Obviously this can be dangerous, so only use it when + absolutely necessary. + + @param index the index of the element being requested (0 is the first element in the array) + @see operator[], getFirst, getLast */ - inline ObjectClass* getFirst() const throw() + inline ElementType& getReference (const int index) const throw() { lock.enter(); - ObjectClass* const result = (numUsed > 0) ? data.elements [0] - : (ObjectClass*) 0; + jassert (((unsigned int) index) < (unsigned int) numUsed); + ElementType& result = data.elements [index]; lock.exit(); return result; } - /** Returns a pointer to the last object in the array. + /** Returns the first element in the array, or 0 if the array is empty. - This will return a null pointer if the array's empty. - @see getFirst + @see operator[], getUnchecked, getLast */ - inline ObjectClass* getLast() const throw() + inline ElementType getFirst() const throw() { lock.enter(); - ObjectClass* const result = (numUsed > 0) ? data.elements [numUsed - 1] - : (ObjectClass*) 0; + const ElementType result = (numUsed > 0) ? data.elements [0] + : ElementType(); lock.exit(); return result; } - /** Finds the index of an object which might be in the array. + /** Returns the last element in the array, or 0 if the array is empty. - @param objectToLookFor the object to look for - @returns the index at which the object was found, or -1 if it's not found + @see operator[], getUnchecked, getFirst */ - int indexOf (const ObjectClass* const objectToLookFor) const throw() + inline ElementType getLast() const throw() + { + lock.enter(); + const ElementType result = (numUsed > 0) ? data.elements [numUsed - 1] + : ElementType(); + lock.exit(); + + return result; + } + + /** Finds the index of the first element which matches the value passed in. + + This will search the array for the given object, and return the index + of its first occurrence. If the object isn't found, the method will return -1. + + @param elementToLookFor the value or object to look for + @returns the index of the object, or -1 if it's not found + */ + int indexOf (const ElementType elementToLookFor) const throw() { int result = -1; lock.enter(); - ObjectClass* const* e = data.elements; + const ElementType* e = data.elements; for (int i = numUsed; --i >= 0;) { - if (objectToLookFor == *e) + if (elementToLookFor == *e) { result = (int) (e - data.elements); break; @@ -3471,42 +3446,42 @@ public: return result; } - /** Returns true if the array contains a specified object. + /** Returns true if the array contains at least one occurrence of an object. - @param objectToLookFor the object to look for - @returns true if the object is in the array + @param elementToLookFor the value or object to look for + @returns true if the item is found */ - bool contains (const ObjectClass* const objectToLookFor) const throw() + bool contains (const ElementType elementToLookFor) const throw() { lock.enter(); - ObjectClass* const* e = data.elements; - int i = numUsed; + const ElementType* e = data.elements; + int num = numUsed; - while (i >= 4) + while (num >= 4) { - if (objectToLookFor == *e - || objectToLookFor == *++e - || objectToLookFor == *++e - || objectToLookFor == *++e) + if (*e == elementToLookFor + || *++e == elementToLookFor + || *++e == elementToLookFor + || *++e == elementToLookFor) { lock.exit(); return true; } - i -= 4; + num -= 4; ++e; } - while (i > 0) + while (num > 0) { - if (objectToLookFor == *e) + if (elementToLookFor == *e) { lock.exit(); return true; } - --i; + --num; ++e; } @@ -3514,157 +3489,299 @@ public: return false; } - /** Appends a new object to the end of the array. + /** Appends a new element at the end of the array. - Note that the this object will be deleted by the OwnedArray when it - is removed, so be careful not to delete it somewhere else. + @param newElement the new object to add to the array + @see set, insert, addIfNotAlreadyThere, addSorted, addArray + */ + void add (const ElementType newElement) throw() + { + lock.enter(); + data.ensureAllocatedSize (numUsed + 1); + data.elements [numUsed++] = newElement; + lock.exit(); + } - Also be careful not to add the same object to the array more than once, - as this will obviously cause deletion of dangling pointers. + /** Inserts a new element into the array at a given position. - @param newObject the new object to add to the array - @see set, insert, addIfNotAlreadyThere, addSorted + If the index is less than 0 or greater than the size of the array, the + element will be added to the end of the array. + Otherwise, it will be inserted into the array, moving all the later elements + along to make room. + + @param indexToInsertAt the index at which the new element should be + inserted (pass in -1 to add it to the end) + @param newElement the new object to add to the array + @see add, addSorted, set */ - void add (const ObjectClass* const newObject) throw() + void insert (int indexToInsertAt, const ElementType newElement) throw() { lock.enter(); data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = const_cast (newObject); + + if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) + { + ElementType* const insertPos = data.elements + indexToInsertAt; + const int numberToMove = numUsed - indexToInsertAt; + + if (numberToMove > 0) + memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); + + *insertPos = newElement; + ++numUsed; + } + else + { + data.elements [numUsed++] = newElement; + } + lock.exit(); } - /** Inserts a new object into the array at the given index. - - Note that the this object will be deleted by the OwnedArray when it - is removed, so be careful not to delete it somewhere else. + /** Inserts multiple copies of an element into the array at a given position. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. - Be careful not to add the same object to the array more than once, - as this will obviously cause deletion of dangling pointers. - - @param indexToInsertAt the index at which the new element should be inserted - @param newObject the new object to add to the array - @see add, addSorted, addIfNotAlreadyThere, set + @param indexToInsertAt the index at which the new element should be inserted + @param newElement the new object to add to the array + @param numberOfTimesToInsertIt how many copies of the value to insert + @see insert, add, addSorted, set */ - void insert (int indexToInsertAt, - const ObjectClass* const newObject) throw() + void insertMultiple (int indexToInsertAt, const ElementType newElement, + int numberOfTimesToInsertIt) throw() { - if (indexToInsertAt >= 0) + if (numberOfTimesToInsertIt > 0) { lock.enter(); + data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt); - if (indexToInsertAt > numUsed) - indexToInsertAt = numUsed; - - data.ensureAllocatedSize (numUsed + 1); - - ObjectClass** const e = data.elements + indexToInsertAt; - const int numToMove = numUsed - indexToInsertAt; + if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) + { + ElementType* insertPos = data.elements + indexToInsertAt; + const int numberToMove = numUsed - indexToInsertAt; - if (numToMove > 0) - memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); + memmove (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove * sizeof (ElementType)); + numUsed += numberOfTimesToInsertIt; - *e = const_cast (newObject); - ++numUsed; + while (--numberOfTimesToInsertIt >= 0) + *insertPos++ = newElement; + } + else + { + while (--numberOfTimesToInsertIt >= 0) + data.elements [numUsed++] = newElement; + } lock.exit(); } - else + } + + /** Inserts an array of values into this array at a given position. + + If the index is less than 0 or greater than the size of the array, the + new elements will be added to the end of the array. + Otherwise, they will be inserted into the array, moving all the later elements + along to make room. + + @param indexToInsertAt the index at which the first new element should be inserted + @param newElements the new values to add to the array + @param numberOfElements how many items are in the array + @see insert, add, addSorted, set + */ + void insertArray (int indexToInsertAt, + const ElementType* newElements, + int numberOfElements) throw() + { + if (numberOfElements > 0) { - add (newObject); + lock.enter(); + data.ensureAllocatedSize (numUsed + numberOfElements); + + if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) + { + ElementType* insertPos = data.elements + indexToInsertAt; + const int numberToMove = numUsed - indexToInsertAt; + + memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType)); + numUsed += numberOfElements; + + while (--numberOfElements >= 0) + *insertPos++ = *newElements++; + } + else + { + while (--numberOfElements >= 0) + data.elements [numUsed++] = *newElements++; + } + + lock.exit(); } } - /** Appends a new object at the end of the array as long as the array doesn't + /** Appends a new element at the end of the array as long as the array doesn't already contain it. - If the array already contains a matching object, nothing will be done. + If the array already contains an element that matches the one passed in, nothing + will be done. - @param newObject the new object to add to the array + @param newElement the new object to add to the array */ - void addIfNotAlreadyThere (const ObjectClass* const newObject) throw() + void addIfNotAlreadyThere (const ElementType newElement) throw() { lock.enter(); - if (! contains (newObject)) - add (newObject); + if (! contains (newElement)) + add (newElement); lock.exit(); } - /** Replaces an object in the array with a different one. + /** Replaces an element with a new value. If the index is less than zero, this method does nothing. - If the index is beyond the end of the array, the new object is added to the end of the array. - - Be careful not to add the same object to the array more than once, - as this will obviously cause deletion of dangling pointers. + If the index is beyond the end of the array, the item is added to the end of the array. - @param indexToChange the index whose value you want to change - @param newObject the new value to set for this index. - @param deleteOldElement whether to delete the object that's being replaced with the new one - @see add, insert, remove + @param indexToChange the index whose value you want to change + @param newValue the new value to set for this index. + @see add, insert */ void set (const int indexToChange, - const ObjectClass* const newObject, - const bool deleteOldElement = true) + const ElementType newValue) throw() { + jassert (indexToChange >= 0); + if (indexToChange >= 0) { - ObjectClass* toDelete = 0; lock.enter(); if (indexToChange < numUsed) { - if (deleteOldElement) - { - toDelete = data.elements [indexToChange]; - - if (toDelete == newObject) - toDelete = 0; - } - - data.elements [indexToChange] = const_cast (newObject); + data.elements [indexToChange] = newValue; } else { data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = const_cast (newObject); + data.elements [numUsed++] = newValue; } lock.exit(); + } + } - delete toDelete; + /** Replaces an element with a new value without doing any bounds-checking. + + This just sets a value directly in the array's internal storage, so you'd + better make sure it's in range! + + @param indexToChange the index whose value you want to change + @param newValue the new value to set for this index. + @see set, getUnchecked + */ + void setUnchecked (const int indexToChange, + const ElementType newValue) throw() + { + lock.enter(); + jassert (((unsigned int) indexToChange) < (unsigned int) numUsed); + data.elements [indexToChange] = newValue; + lock.exit(); + } + + /** Adds elements from an array to the end of this array. + + @param elementsToAdd the array of elements to add + @param numElementsToAdd how many elements are in this other array + @see add + */ + void addArray (const ElementType* elementsToAdd, + int numElementsToAdd) throw() + { + lock.enter(); + + if (numElementsToAdd > 0) + { + data.ensureAllocatedSize (numUsed + numElementsToAdd); + + while (--numElementsToAdd >= 0) + data.elements [numUsed++] = *elementsToAdd++; } + + lock.exit(); } - /** Inserts a new object into the array assuming that the array is sorted. + /** This swaps the contents of this array with those of another array. - This will use a comparator to find the position at which the new object + If you need to exchange two arrays, this is vastly quicker than using copy-by-value + because it just swaps their internal pointers. + */ + template + void swapWithArray (OtherArrayType& otherArray) throw() + { + lock.enter(); + otherArray.lock.enter(); + swapVariables (numUsed, otherArray.numUsed); + swapVariables (data.elements, otherArray.data.elements); + swapVariables (data.numAllocated, otherArray.data.numAllocated); + otherArray.lock.exit(); + lock.exit(); + } + + /** Adds elements from another array to the end of this array. + + @param arrayToAddFrom the array from which to copy the elements + @param startIndex the first element of the other array to start copying from + @param numElementsToAdd how many elements to add from the other array. If this + value is negative or greater than the number of available elements, + all available elements will be copied. + @see add + */ + template + void addArray (const OtherArrayType& arrayToAddFrom, + int startIndex = 0, + int numElementsToAdd = -1) throw() + { + arrayToAddFrom.lockArray(); + lock.enter(); + + if (startIndex < 0) + { + jassertfalse + startIndex = 0; + } + + if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) + numElementsToAdd = arrayToAddFrom.size() - startIndex; + + while (--numElementsToAdd >= 0) + add (arrayToAddFrom.getUnchecked (startIndex++)); + + lock.exit(); + arrayToAddFrom.unlockArray(); + } + + /** Inserts a new element into the array, assuming that the array is sorted. + + This will use a comparator to find the position at which the new element should go. If the array isn't sorted, the behaviour of this method will be unpredictable. - @param comparator the comparator to use to compare the elements - see the sort method - for details about this object's structure - @param newObject the new object to insert to the array - @see add, sort, indexOfSorted + @param comparator the comparator to use to compare the elements - see the sort() + method for details about the form this object should take + @param newElement the new element to insert to the array + @see add, sort */ template void addSorted (ElementComparator& comparator, - ObjectClass* const newObject) throw() + const ElementType newElement) throw() { - (void) comparator; // if you pass in an object with a static compareElements() method, this - // avoids getting warning messages about the parameter being unused lock.enter(); - insert (findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed), newObject); + insert (findInsertIndexInSortedArray (comparator, data.elements, newElement, 0, numUsed), newElement); lock.exit(); } - /** Finds the index of an object in the array, assuming that the array is sorted. + /** Finds the index of an element in the array, assuming that the array is sorted. This will use a comparator to do a binary-chop to find the index of the given element, if it exists. If the array isn't sorted, the behaviour of this @@ -3672,13 +3789,13 @@ public: @param comparator the comparator to use to compare the elements - see the sort() method for details about the form this object should take - @param objectToLookFor the object to search for + @param elementToLookFor the element to search for @returns the index of the element, or -1 if it's not found @see addSorted, sort */ template int indexOfSorted (ElementComparator& comparator, - const ObjectClass* const objectToLookFor) const throw() + const ElementType elementToLookFor) const throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused @@ -3694,7 +3811,7 @@ public: lock.exit(); return -1; } - else if (comparator.compareElements (objectToLookFor, data.elements [start]) == 0) + else if (comparator.compareElements (elementToLookFor, data.elements [start]) == 0) { lock.exit(); return start; @@ -3708,7 +3825,7 @@ public: lock.exit(); return -1; } - else if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0) + else if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) start = halfway; else end = halfway; @@ -3716,63 +3833,62 @@ public: } } - /** Removes an object from the array. + /** Removes an element from the array. - This will remove the object at a given index (optionally also - deleting it) and move back all the subsequent objects to close the gap. + This will remove the element at a given index, and move back + all the subsequent elements to close the gap. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove - @param deleteObject whether to delete the object that is removed - @see removeObject, removeRange + @returns the element that has been removed + @see removeValue, removeRange */ - void remove (const int indexToRemove, - const bool deleteObject = true) + ElementType remove (const int indexToRemove) throw() { lock.enter(); - ObjectClass* toDelete = 0; if (((unsigned int) indexToRemove) < (unsigned int) numUsed) { - ObjectClass** const e = data.elements + indexToRemove; - - if (deleteObject) - toDelete = *e; - --numUsed; - const int numToShift = numUsed - indexToRemove; - if (numToShift > 0) - memmove (e, e + 1, numToShift * sizeof (ObjectClass*)); + ElementType* const e = data.elements + indexToRemove; + ElementType const removed = *e; + const int numberToShift = numUsed - indexToRemove; + + if (numberToShift > 0) + memmove (e, e + 1, numberToShift * sizeof (ElementType)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); - } - - lock.exit(); - delete toDelete; + lock.exit(); + return removed; + } + else + { + lock.exit(); + return ElementType(); + } } - /** Removes a specified object from the array. + /** Removes an item from the array. + This will remove the first occurrence of the given element from the array. If the item isn't found, no action is taken. - @param objectToRemove the object to try to remove - @param deleteObject whether to delete the object (if it's found) + @param valueToRemove the object to try to remove @see remove, removeRange */ - void removeObject (const ObjectClass* const objectToRemove, - const bool deleteObject = true) + void removeValue (const ElementType valueToRemove) throw() { lock.enter(); - ObjectClass** e = data.elements; + ElementType* e = data.elements; for (int i = numUsed; --i >= 0;) { - if (objectToRemove == *e) + if (valueToRemove == *e) { - remove ((int) (e - data.elements), deleteObject); + remove ((int) (e - data.elements)); break; } @@ -3782,22 +3898,20 @@ public: lock.exit(); } - /** Removes a range of objects from the array. + /** Removes a range of elements from the array. - This will remove a set of objects, starting from the given index, - and move any subsequent elements down to close the gap. + This will remove a set of elements, starting from the given index, + and move subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. - @param startIndex the index of the first object to remove - @param numberToRemove how many objects should be removed - @param deleteObjects whether to delete the objects that get removed - @see remove, removeObject + @param startIndex the index of the first element to remove + @param numberToRemove how many elements should be removed + @see remove, removeValue */ void removeRange (int startIndex, - const int numberToRemove, - const bool deleteObjects = true) + const int numberToRemove) throw() { lock.enter(); const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); @@ -3805,17 +3919,8 @@ public: if (endIndex > startIndex) { - if (deleteObjects) - { - for (int i = startIndex; i < endIndex; ++i) - { - delete data.elements [i]; - data.elements [i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) - } - } - const int rangeSize = endIndex - startIndex; - ObjectClass** e = data.elements + startIndex; + ElementType* e = data.elements + startIndex; int numToShift = numUsed - endIndex; numUsed -= rangeSize; @@ -3832,34 +3937,89 @@ public: lock.exit(); } - /** Removes the last n objects from the array. + /** Removes the last n elements from the array. - @param howManyToRemove how many objects to remove from the end of the array - @param deleteObjects whether to also delete the objects that are removed - @see remove, removeObject, removeRange + @param howManyToRemove how many elements to remove from the end of the array + @see remove, removeValue, removeRange */ - void removeLast (int howManyToRemove = 1, - const bool deleteObjects = true) + void removeLast (const int howManyToRemove = 1) throw() { lock.enter(); + numUsed = jmax (0, numUsed - howManyToRemove); - if (howManyToRemove >= numUsed) + if ((numUsed << 1) < data.numAllocated) + minimiseStorageOverheads(); + + lock.exit(); + } + + /** Removes any elements which are also in another array. + + @param otherArray the other array in which to look for elements to remove + @see removeValuesNotIn, remove, removeValue, removeRange + */ + template + void removeValuesIn (const OtherArrayType& otherArray) throw() + { + otherArray.lockArray(); + lock.enter(); + + if (this == &otherArray) { - clear (deleteObjects); + clear(); } else { - while (--howManyToRemove >= 0) - remove (numUsed - 1, deleteObjects); + if (otherArray.size() > 0) + { + for (int i = numUsed; --i >= 0;) + if (otherArray.contains (data.elements [i])) + remove (i); + } } lock.exit(); + otherArray.unlockArray(); } - /** Swaps a pair of objects in the array. + /** Removes any elements which are not found in another array. - If either of the indexes passed in is out-of-range, nothing will happen, - otherwise the two objects at these positions will be exchanged. + Only elements which occur in this other array will be retained. + + @param otherArray the array in which to look for elements NOT to remove + @see removeValuesIn, remove, removeValue, removeRange + */ + template + void removeValuesNotIn (const OtherArrayType& otherArray) throw() + { + otherArray.lockArray(); + lock.enter(); + + if (this != &otherArray) + { + if (otherArray.size() <= 0) + { + clear(); + } + else + { + for (int i = numUsed; --i >= 0;) + if (! otherArray.contains (data.elements [i])) + remove (i); + } + } + + lock.exit(); + otherArray.unlockArray(); + } + + /** Swaps over two elements in the array. + + This swaps over the elements found at the two indexes passed in. + If either index is out-of-range, this method will do nothing. + + @param index1 index of one of the elements to swap + @param index2 index of the other element to swap */ void swap (const int index1, const int index2) throw() @@ -3867,7 +4027,7 @@ public: lock.enter(); if (((unsigned int) index1) < (unsigned int) numUsed - && ((unsigned int) index2) < (unsigned int) numUsed) + && ((unsigned int) index2) < (unsigned int) numUsed) { swapVariables (data.elements [index1], data.elements [index2]); @@ -3876,18 +4036,19 @@ public: lock.exit(); } - /** Moves one of the objects to a different position. + /** Moves one of the values to a different position. - This will move the object to a specified index, shuffling along + This will move the value to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. - @param currentIndex the index of the object to be moved. If this isn't a + @param currentIndex the index of the value to be moved. If this isn't a valid index, then nothing will be done - @param newIndex the index at which you'd like this object to end up. If this - is less than zero, it will be moved to the end of the array + @param newIndex the index at which you'd like this value to end up. If this + is less than zero, the value will be moved to the end + of the array */ void move (const int currentIndex, int newIndex) throw() @@ -3901,19 +4062,19 @@ public: if (((unsigned int) newIndex) >= (unsigned int) numUsed) newIndex = numUsed - 1; - ObjectClass* const value = data.elements [currentIndex]; + const ElementType value = data.elements [currentIndex]; if (newIndex > currentIndex) { memmove (data.elements + currentIndex, data.elements + currentIndex + 1, - (newIndex - currentIndex) * sizeof (ObjectClass*)); + (newIndex - currentIndex) * sizeof (ElementType)); } else { memmove (data.elements + newIndex + 1, data.elements + newIndex, - (currentIndex - newIndex) * sizeof (ObjectClass*)); + (currentIndex - newIndex) * sizeof (ElementType)); } data.elements [newIndex] = value; @@ -3923,23 +4084,6 @@ public: } } - /** This swaps the contents of this array with those of another array. - - If you need to exchange two arrays, this is vastly quicker than using copy-by-value - because it just swaps their internal pointers. - */ - template - void swapWithArray (OtherArrayType& otherArray) throw() - { - lock.enter(); - otherArray.lock.enter(); - swapVariables (numUsed, otherArray.numUsed); - swapVariables (data.elements, otherArray.data.elements); - swapVariables (data.numAllocated, otherArray.data.numAllocated); - otherArray.lock.exit(); - lock.exit(); - } - /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after @@ -3999,7 +4143,8 @@ public: be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. - @see sortArray, indexOfSorted + + @see addSorted, indexOfSorted, sortArray */ template void sort (ElementComparator& comparator, @@ -4007,7 +4152,6 @@ public: { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused - lock.enter(); sortArray (comparator, data.elements, 0, size() - 1, retainOrderOfEquivalentItems); lock.exit(); @@ -4040,879 +4184,952 @@ public: juce_UseDebuggingNewOperator private: - ArrayAllocationBase data; + ArrayAllocationBase data; int numUsed; TypeOfCriticalSectionToUse lock; - - // disallow copy constructor and assignment - OwnedArray (const OwnedArray&); - const OwnedArray& operator= (const OwnedArray&); }; -#endif // __JUCE_OWNEDARRAY_JUCEHEADER__ -/********* End of inlined file: juce_OwnedArray.h *********/ +#endif // __JUCE_ARRAY_JUCEHEADER__ +/********* End of inlined file: juce_Array.h *********/ -/********* Start of inlined file: juce_Time.h *********/ -#ifndef __JUCE_TIME_JUCEHEADER__ -#define __JUCE_TIME_JUCEHEADER__ +#endif +#ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ -/********* Start of inlined file: juce_RelativeTime.h *********/ -#ifndef __JUCE_RELATIVETIME_JUCEHEADER__ -#define __JUCE_RELATIVETIME_JUCEHEADER__ +#endif +#ifndef __JUCE_BITARRAY_JUCEHEADER__ -/** A relative measure of time. +/********* Start of inlined file: juce_BitArray.h *********/ +#ifndef __JUCE_BITARRAY_JUCEHEADER__ +#define __JUCE_BITARRAY_JUCEHEADER__ - The time is stored as a number of seconds, at double-precision floating - point accuracy, and may be positive or negative. +/********* Start of inlined file: juce_HeapBlock.h *********/ +#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ +#define __JUCE_HEAPBLOCK_JUCEHEADER__ - If you need an absolute time, (i.e. a date + time), see the Time class. -*/ -class JUCE_API RelativeTime -{ -public: +/** + Very simple container class to hold a pointer to some data on the heap. - /** Creates a RelativeTime. + When you need to allocate some heap storage for something, always try to use + this class instead of allocating the memory directly using malloc/free. - @param seconds the number of seconds, which may be +ve or -ve. - @see milliseconds, minutes, hours, days, weeks - */ - explicit RelativeTime (const double seconds = 0.0) throw(); + A HeapBlock object can be treated in pretty much exactly the same way + as an char*, but as long as you allocate it on the stack or as a class member, + it's almost impossible for it to leak memory. - /** Copies another relative time. */ - RelativeTime (const RelativeTime& other) throw(); + It also makes your code much more concise and readable than doing the same thing + using direct allocations, - /** Copies another relative time. */ - const RelativeTime& operator= (const RelativeTime& other) throw(); + E.g. instead of this: + @code + int* temp = (int*) juce_malloc (1024 * sizeof (int)); + memcpy (temp, xyz, 1024 * sizeof (int)); + juce_free (temp); + temp = (int*) juce_calloc (2048 * sizeof (int)); + temp[0] = 1234; + memcpy (foobar, temp, 2048 * sizeof (int)); + juce_free (temp); + @endcode - /** Destructor. */ - ~RelativeTime() throw(); + ..you could just write this: + @code + HeapBlock temp (1024); + memcpy (temp, xyz, 1024 * sizeof (int)); + temp.calloc (2048); + temp[0] = 1234; + memcpy (foobar, temp, 2048 * sizeof (int)); + @endcode - /** Creates a new RelativeTime object representing a number of milliseconds. + The class is extremely lightweight, containing only a pointer to the + data, and exposes malloc/realloc/calloc/free methods that do the same jobs + as their less object-oriented counterparts. Despite adding safety, you probably + won't sacrifice any performance by using this in place of normal pointers. - @see minutes, hours, days, weeks - */ - static const RelativeTime milliseconds (const int milliseconds) throw(); + @see Array, OwnedArray, MemoryBlock +*/ +template +class HeapBlock +{ +public: - /** Creates a new RelativeTime object representing a number of milliseconds. + /** Creates a HeapBlock which is initially just a null pointer. - @see minutes, hours, days, weeks + After creation, you can resize the array using the malloc(), calloc(), + or realloc() methods. */ - static const RelativeTime milliseconds (const int64 milliseconds) throw(); - - /** Creates a new RelativeTime object representing a number of minutes. + HeapBlock() : data (0) + { + } - @see milliseconds, hours, days, weeks - */ - static const RelativeTime minutes (const double numberOfMinutes) throw(); + /** Creates a HeapBlock containing a number of elements. - /** Creates a new RelativeTime object representing a number of hours. + The contents of the block are undefined, as it will have been created by a + malloc call. - @see milliseconds, minutes, days, weeks + If you want an array of zero values, you can use the calloc() method instead. */ - static const RelativeTime hours (const double numberOfHours) throw(); + HeapBlock (const int numElements) + : data ((ElementType*) ::juce_malloc (numElements * sizeof (ElementType))) + { + } - /** Creates a new RelativeTime object representing a number of days. + /** Destructor. - @see milliseconds, minutes, hours, weeks + This will free the data, if any has been allocated. */ - static const RelativeTime days (const double numberOfDays) throw(); - - /** Creates a new RelativeTime object representing a number of weeks. + ~HeapBlock() + { + ::juce_free (data); + } - @see milliseconds, minutes, hours, days + /** Returns a raw pointer to the allocated data. + This may be a null pointer if the data hasn't yet been allocated, or if it has been + freed by calling the free() method. */ - static const RelativeTime weeks (const double numberOfWeeks) throw(); - - /** Returns the number of milliseconds this time represents. + inline operator ElementType*() const { return data; } - @see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks + /** Returns a void pointer to the allocated data. + This may be a null pointer if the data hasn't yet been allocated, or if it has been + freed by calling the free() method. */ - int64 inMilliseconds() const throw(); - - /** Returns the number of seconds this time represents. + inline operator void*() const { return (void*) data; } - @see inMilliseconds, inMinutes, inHours, inDays, inWeeks + /** Lets you use indirect calls to the first element in the array. + Obviously this will cause problems if the array hasn't been initialised, because it'll + be referencing a null pointer. */ - double inSeconds() const throw() { return seconds; } - - /** Returns the number of minutes this time represents. + inline ElementType* operator->() const { return data; } - @see inMilliseconds, inSeconds, inHours, inDays, inWeeks + /** Returns a pointer to the data by casting it to any type you need. */ - double inMinutes() const throw(); - - /** Returns the number of hours this time represents. + template + inline operator CastType*() const { return (CastType*) data; } - @see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks + /** Returns a reference to one of the data elements. + Obviously there's no bounds-checking here, as this object is just a dumb pointer and + has no idea of the size it currently has allocated. */ - double inHours() const throw(); - - /** Returns the number of days this time represents. + inline ElementType& operator[] (const pointer_sized_int index) const { return data [index]; } - @see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks + /** Returns a pointer to a data element at an offset from the start of the array. + This is the same as doing pointer arithmetic on the raw pointer itself. */ - double inDays() const throw(); + inline ElementType* operator+ (const pointer_sized_int index) const { return data + index; } - /** Returns the number of weeks this time represents. + /** Returns a reference to the raw data pointer. + Beware that the pointer returned here will become invalid as soon as you call + any of the allocator methods on this object! + */ + inline ElementType** operator&() const { return (ElementType**) &data; } - @see inMilliseconds, inSeconds, inMinutes, inHours, inDays + /** Compares the pointer with another pointer. + This can be handy for checking whether this is a null pointer. */ - double inWeeks() const throw(); + inline bool operator== (const ElementType* const otherPointer) const { return otherPointer == data; } - /** Returns a readable textual description of the time. + /** Compares the pointer with another pointer. + This can be handy for checking whether this is a null pointer. + */ + inline bool operator!= (const ElementType* const otherPointer) const { return otherPointer != data; } - The exact format of the string returned will depend on - the magnitude of the time - e.g. + /** Allocates a specified amount of memory. - "1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms" + This uses the normal malloc to allocate an amount of memory for this object. + Any previously allocated memory will be freed by this method. - so that only the two most significant units are printed. + The number of bytes allocated will be (newNumElements * elementSize). Normally + you wouldn't need to specify the second parameter, but it can be handy if you need + to allocate a size in bytes rather than in terms of the number of elements. - The returnValueForZeroTime value is the result that is returned if the - length is zero. Depending on your application you might want to use this - to return something more relevant like "empty" or "0 secs", etc. + The data that is allocated will be freed when this object is deleted, or when you + call free() or any of the allocation methods. + */ + void malloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + ::juce_free (data); + data = (ElementType*) ::juce_malloc (newNumElements * elementSize); + } - @see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks + /** Allocates a specified amount of memory and clears it. + This does the same job as the malloc() method, but clears the memory that it allocates. */ - const String getDescription (const String& returnValueForZeroTime = JUCE_T("0")) const throw(); + void calloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + ::juce_free (data); + data = (ElementType*) ::juce_calloc (newNumElements * elementSize); + } - /** Compares two RelativeTimes. */ - bool operator== (const RelativeTime& other) const throw(); - /** Compares two RelativeTimes. */ - bool operator!= (const RelativeTime& other) const throw(); + /** Allocates a specified amount of memory and optionally clears it. + This does the same job as either malloc() or calloc(), depending on the + initialiseToZero parameter. + */ + void allocate (const int newNumElements, const bool initialiseToZero) + { + ::juce_free (data); - /** Compares two RelativeTimes. */ - bool operator> (const RelativeTime& other) const throw(); - /** Compares two RelativeTimes. */ - bool operator< (const RelativeTime& other) const throw(); - /** Compares two RelativeTimes. */ - bool operator>= (const RelativeTime& other) const throw(); - /** Compares two RelativeTimes. */ - bool operator<= (const RelativeTime& other) const throw(); + if (initialiseToZero) + data = (ElementType*) ::juce_calloc (newNumElements * sizeof (ElementType)); + else + data = (ElementType*) ::juce_malloc (newNumElements * sizeof (ElementType)); + } - /** Adds another RelativeTime to this one and returns the result. */ - const RelativeTime operator+ (const RelativeTime& timeToAdd) const throw(); - /** Subtracts another RelativeTime from this one and returns the result. */ - const RelativeTime operator- (const RelativeTime& timeToSubtract) const throw(); + /** Re-allocates a specified amount of memory. - /** Adds a number of seconds to this RelativeTime and returns the result. */ - const RelativeTime operator+ (const double secondsToAdd) const throw(); - /** Subtracts a number of seconds from this RelativeTime and returns the result. */ - const RelativeTime operator- (const double secondsToSubtract) const throw(); + The semantics of this method are the same as malloc() and calloc(), but it + uses realloc() to keep as much of the existing data as possible. + */ + void realloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + if (data == 0) + data = (ElementType*) ::juce_malloc (newNumElements * elementSize); + else + data = (ElementType*) ::juce_realloc (data, newNumElements * elementSize); + } - /** Adds another RelativeTime to this one. */ - const RelativeTime& operator+= (const RelativeTime& timeToAdd) throw(); - /** Subtracts another RelativeTime from this one. */ - const RelativeTime& operator-= (const RelativeTime& timeToSubtract) throw(); + /** Frees any currently-allocated data. + This will free the data and reset this object to be a null pointer. + */ + void free() + { + ::juce_free (data); + data = 0; + } - /** Adds a number of seconds to this time. */ - const RelativeTime& operator+= (const double secondsToAdd) throw(); + /** Swaps this object's data with the data of another HeapBlock. + The two objects simply exchange their data pointers. + */ + void swapWith (HeapBlock & other) + { + swapVariables (data, other.data); + } - /** Subtracts a number of seconds from this time. */ - const RelativeTime& operator-= (const double secondsToSubtract) throw(); +private: - juce_UseDebuggingNewOperator + ElementType* data; -private: - double seconds; + HeapBlock (const HeapBlock&); + const HeapBlock& operator= (const HeapBlock&); }; -#endif // __JUCE_RELATIVETIME_JUCEHEADER__ -/********* End of inlined file: juce_RelativeTime.h *********/ +#endif // __JUCE_HEAPBLOCK_JUCEHEADER__ +/********* End of inlined file: juce_HeapBlock.h *********/ -/** - Holds an absolute date and time. +class MemoryBlock; - Internally, the time is stored at millisecond precision. +/** + An array of on/off bits, also usable to store large binary integers. - @see RelativeTime + A BitArray acts like an arbitrarily large integer whose bits can be set or + cleared, and some basic mathematical operations can be done on the number as + a whole. */ -class JUCE_API Time +class JUCE_API BitArray { public: - /** Creates a Time object. - - This default constructor creates a time of 1st January 1970, (which is - represented internally as 0ms). + /** Creates an empty BitArray */ + BitArray() throw(); - To create a time object representing the current time, use getCurrentTime(). + /** Creates a BitArray containing an integer value in its low bits. - @see getCurrentTime + The low 32 bits of the array are initialised with this value. */ - Time() throw(); + BitArray (const unsigned int value) throw(); - /** Creates a copy of another Time object. */ - Time (const Time& other) throw(); + /** Creates a BitArray containing an integer value in its low bits. - /** Creates a time based on a number of milliseconds. + The low 32 bits of the array are initialised with the absolute value + passed in, and its sign is set to reflect the sign of the number. + */ + BitArray (const int value) throw(); - The internal millisecond count is set to 0 (1st January 1970). To create a - time object set to the current time, use getCurrentTime(). + /** Creates a BitArray containing an integer value in its low bits. - @param millisecondsSinceEpoch the number of milliseconds since the unix - 'epoch' (midnight Jan 1st 1970). - @see getCurrentTime, currentTimeMillis + The low 64 bits of the array are initialised with the absolute value + passed in, and its sign is set to reflect the sign of the number. */ - Time (const int64 millisecondsSinceEpoch) throw(); + BitArray (int64 value) throw(); - /** Creates a time from a set of date components. + /** Creates a copy of another BitArray. */ + BitArray (const BitArray& other) throw(); - The timezone is assumed to be whatever the system is using as its locale. + /** Destructor. */ + ~BitArray() throw(); - @param year the year, in 4-digit format, e.g. 2004 - @param month the month, in the range 0 to 11 - @param day the day of the month, in the range 1 to 31 - @param hours hours in 24-hour clock format, 0 to 23 - @param minutes minutes 0 to 59 - @param seconds seconds 0 to 59 - @param milliseconds milliseconds 0 to 999 - @param useLocalTime if true, encode using the current machine's local time; if - false, it will always work in GMT. - */ - Time (const int year, - const int month, - const int day, - const int hours, - const int minutes, - const int seconds = 0, - const int milliseconds = 0, - const bool useLocalTime = true) throw(); + /** Copies another BitArray onto this one. */ + const BitArray& operator= (const BitArray& other) throw(); - /** Destructor. */ - ~Time() throw(); + /** Two arrays are the same if the same bits are set. */ + bool operator== (const BitArray& other) const throw(); + /** Two arrays are the same if the same bits are set. */ + bool operator!= (const BitArray& other) const throw(); - /** Copies this time from another one. */ - const Time& operator= (const Time& other) throw(); + /** Clears all bits in the BitArray to 0. */ + void clear() throw(); - /** Returns a Time object that is set to the current system time. + /** Clears a particular bit in the array. */ + void clearBit (const int bitNumber) throw(); - @see currentTimeMillis + /** Sets a specified bit to 1. + + If the bit number is high, this will grow the array to accomodate it. */ - static const Time JUCE_CALLTYPE getCurrentTime() throw(); + void setBit (const int bitNumber) throw(); - /** Returns the time as a number of milliseconds. + /** Sets or clears a specified bit. */ + void setBit (const int bitNumber, + const bool shouldBeSet) throw(); - @returns the number of milliseconds this Time object represents, since - midnight jan 1st 1970. - @see getMilliseconds + /** Sets a range of bits to be either on or off. + + @param startBit the first bit to change + @param numBits the number of bits to change + @param shouldBeSet whether to turn these bits on or off */ - int64 toMilliseconds() const throw() { return millisSinceEpoch; } + void setRange (int startBit, + int numBits, + const bool shouldBeSet) throw(); - /** Returns the year. + /** Inserts a bit an a given position, shifting up any bits above it. */ + void insertBit (const int bitNumber, + const bool shouldBeSet) throw(); - A 4-digit format is used, e.g. 2004. + /** Returns the value of a specified bit in the array. + + If the index is out-of-range, the result will be false. */ - int getYear() const throw(); + bool operator[] (const int bit) const throw(); - /** Returns the number of the month. + /** Returns true if no bits are set. */ + bool isEmpty() const throw(); - The value returned is in the range 0 to 11. - @see getMonthName + /** Returns a range of bits in the array as a new BitArray. + + e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits. + @see getBitRangeAsInt */ - int getMonth() const throw(); + const BitArray getBitRange (int startBit, int numBits) const throw(); - /** Returns the name of the month. + /** Returns a range of bits in the array as an integer value. - @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false - it'll return the long form, e.g. "January" - @see getMonth + e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits. + + Asking for more than 32 bits isn't allowed (obviously) - for that, use + getBitRange(). */ - const String getMonthName (const bool threeLetterVersion) const throw(); + int getBitRangeAsInt (int startBit, int numBits) const throw(); - /** Returns the day of the month. + /** Sets a range of bits in the array based on an integer value. - The value returned is in the range 1 to 31. + Copies the given integer into the array, starting at startBit, + and only using up to numBits of the available bits. */ - int getDayOfMonth() const throw(); + void setBitRangeAsInt (int startBit, int numBits, + unsigned int valueToSet) throw(); - /** Returns the number of the day of the week. + /** Performs a bitwise OR with another BitArray. - The value returned is in the range 0 to 6 (0 = sunday, 1 = monday, etc). + The result ends up in this array. */ - int getDayOfWeek() const throw(); + void orWith (const BitArray& other) throw(); - /** Returns the name of the weekday. + /** Performs a bitwise AND with another BitArray. - @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if - false, it'll return the full version, e.g. "Tuesday". + The result ends up in this array. */ - const String getWeekdayName (const bool threeLetterVersion) const throw(); - - /** Returns the number of hours since midnight. + void andWith (const BitArray& other) throw(); - This is in 24-hour clock format, in the range 0 to 23. + /** Performs a bitwise XOR with another BitArray. - @see getHoursInAmPmFormat, isAfternoon + The result ends up in this array. */ - int getHours() const throw(); - - /** Returns true if the time is in the afternoon. + void xorWith (const BitArray& other) throw(); - So it returns true for "PM", false for "AM". + /** Adds another BitArray's value to this one. - @see getHoursInAmPmFormat, getHours + Treating the two arrays as large positive integers, this + adds them up and puts the result in this array. */ - bool isAfternoon() const throw(); + void add (const BitArray& other) throw(); - /** Returns the hours in 12-hour clock format. + /** Subtracts another BitArray's value from this one. - This will return a value 1 to 12 - use isAfternoon() to find out - whether this is in the afternoon or morning. + Treating the two arrays as large positive integers, this + subtracts them and puts the result in this array. - @see getHours, isAfternoon + Note that if the result should be negative, this won't be + handled correctly. */ - int getHoursInAmPmFormat() const throw(); - - /** Returns the number of minutes, 0 to 59. */ - int getMinutes() const throw(); + void subtract (const BitArray& other) throw(); - /** Returns the number of seconds, 0 to 59. */ - int getSeconds() const throw(); + /** Multiplies another BitArray's value with this one. - /** Returns the number of milliseconds, 0 to 999. + Treating the two arrays as large positive integers, this + multiplies them and puts the result in this array. + */ + void multiplyBy (const BitArray& other) throw(); - Unlike toMilliseconds(), this just returns the position within the - current second rather than the total number since the epoch. + /** Divides another BitArray's value into this one and also produces a remainder. - @see toMilliseconds + Treating the two arrays as large positive integers, this + divides this value by the other, leaving the quotient in this + array, and the remainder is copied into the other BitArray passed in. */ - int getMilliseconds() const throw(); + void divideBy (const BitArray& divisor, BitArray& remainder) throw(); - /** Returns true if the local timezone uses a daylight saving correction. */ - bool isDaylightSavingTime() const throw(); + /** Returns the largest value that will divide both this value and the one + passed-in. + */ + const BitArray findGreatestCommonDivisor (BitArray other) const throw(); - /** Returns a 3-character string to indicate the local timezone. */ - const String getTimeZone() const throw(); + /** Performs a modulo operation on this value. - /** Quick way of getting a string version of a date and time. + The result is stored in this value. + */ + void modulo (const BitArray& divisor) throw(); - For a more powerful way of formatting the date and time, see the formatted() method. + /** Performs a combined exponent and modulo operation. - @param includeDate whether to include the date in the string - @param includeTime whether to include the time in the string - @param includeSeconds if the time is being included, this provides an option not to include - the seconds in it - @param use24HourClock if the time is being included, sets whether to use am/pm or 24 - hour notation. - @see formatted + This BitArray's value becomes (this ^ exponent) % modulus. */ - const String toString (const bool includeDate, - const bool includeTime, - const bool includeSeconds = true, - const bool use24HourClock = false) const throw(); + void exponentModulo (const BitArray& exponent, const BitArray& modulus) throw(); - /** Converts this date/time to a string with a user-defined format. + /** Performs an inverse modulo on the value. - This uses the C strftime() function to format this time as a string. To save you - looking it up, these are the escape codes that strftime uses (other codes might - work on some platforms and not others, but these are the common ones): + i.e. the result is (this ^ -1) mod (modulus). + */ + void inverseModulo (const BitArray& modulus) throw(); - %a is replaced by the locale's abbreviated weekday name. - %A is replaced by the locale's full weekday name. - %b is replaced by the locale's abbreviated month name. - %B is replaced by the locale's full month name. - %c is replaced by the locale's appropriate date and time representation. - %d is replaced by the day of the month as a decimal number [01,31]. - %H is replaced by the hour (24-hour clock) as a decimal number [00,23]. - %I is replaced by the hour (12-hour clock) as a decimal number [01,12]. - %j is replaced by the day of the year as a decimal number [001,366]. - %m is replaced by the month as a decimal number [01,12]. - %M is replaced by the minute as a decimal number [00,59]. - %p is replaced by the locale's equivalent of either a.m. or p.m. - %S is replaced by the second as a decimal number [00,61]. - %U is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. - %w is replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. - %W is replaced by the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. - %x is replaced by the locale's appropriate date representation. - %X is replaced by the locale's appropriate time representation. - %y is replaced by the year without century as a decimal number [00,99]. - %Y is replaced by the year with century as a decimal number. - %Z is replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. - %% is replaced by %. + /** Shifts a section of bits left or right. - @see toString + @param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right). + @param startBit the first bit to affect - if this is > 0, only bits above that index will be affected. */ - const String formatted (const tchar* const format) const throw(); - - /** Adds a RelativeTime to this time and returns the result. */ - const Time operator+ (const RelativeTime& delta) const throw() { return Time (millisSinceEpoch + delta.inMilliseconds()); } + void shiftBits (int howManyBitsLeft, + int startBit = 0) throw(); - /** Subtracts a RelativeTime from this time and returns the result. */ - const Time operator- (const RelativeTime& delta) const throw() { return Time (millisSinceEpoch - delta.inMilliseconds()); } + /** Does a signed comparison of two BitArrays. - /** Returns the relative time difference between this time and another one. */ - const RelativeTime operator- (const Time& other) const throw() { return RelativeTime::milliseconds (millisSinceEpoch - other.millisSinceEpoch); } + Return values are: + - 0 if the numbers are the same + - < 0 if this number is smaller than the other + - > 0 if this number is bigger than the other + */ + int compare (const BitArray& other) const throw(); - /** Compares two Time objects. */ - bool operator== (const Time& other) const throw() { return millisSinceEpoch == other.millisSinceEpoch; } + /** Compares the magnitudes of two BitArrays, ignoring their signs. - /** Compares two Time objects. */ - bool operator!= (const Time& other) const throw() { return millisSinceEpoch != other.millisSinceEpoch; } + Return values are: + - 0 if the numbers are the same + - < 0 if this number is smaller than the other + - > 0 if this number is bigger than the other + */ + int compareAbsolute (const BitArray& other) const throw(); - /** Compares two Time objects. */ - bool operator< (const Time& other) const throw() { return millisSinceEpoch < other.millisSinceEpoch; } + /** Returns true if the value is less than zero. - /** Compares two Time objects. */ - bool operator<= (const Time& other) const throw() { return millisSinceEpoch <= other.millisSinceEpoch; } + @see setNegative, negate + */ + bool isNegative() const throw(); - /** Compares two Time objects. */ - bool operator> (const Time& other) const throw() { return millisSinceEpoch > other.millisSinceEpoch; } + /** Changes the sign of the number to be positive or negative. - /** Compares two Time objects. */ - bool operator>= (const Time& other) const throw() { return millisSinceEpoch >= other.millisSinceEpoch; } + @see isNegative, negate + */ + void setNegative (const bool shouldBeNegative) throw(); - /** Tries to set the computer's clock. + /** Inverts the sign of the number. - @returns true if this succeeds, although depending on the system, the - application might not have sufficient privileges to do this. + @see isNegative, setNegative */ - bool setSystemTimeToThisTime() const throw(); + void negate() throw(); - /** Returns the name of a day of the week. + /** Counts the total number of set bits in the array. */ + int countNumberOfSetBits() const throw(); - @param dayNumber the day, 0 to 6 (0 = sunday, 1 = monday, etc) - @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if - false, it'll return the full version, e.g. "Tuesday". - */ - static const String getWeekdayName (int dayNumber, - const bool threeLetterVersion) throw(); + /** Looks for the index of the next set bit after a given starting point. - /** Returns the name of one of the months. + searches from startIndex (inclusive) upwards for the first set bit, + and returns its index. - @param monthNumber the month, 0 to 11 - @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false - it'll return the long form, e.g. "January" + If no set bits are found, it returns -1. */ - static const String getMonthName (int monthNumber, - const bool threeLetterVersion) throw(); + int findNextSetBit (int startIndex = 0) const throw(); - // Static methods for getting system timers directly.. + /** Looks for the index of the next clear bit after a given starting point. - /** Returns the current system time. + searches from startIndex (inclusive) upwards for the first clear bit, + and returns its index. + */ + int findNextClearBit (int startIndex = 0) const throw(); - Returns the number of milliseconds since midnight jan 1st 1970. + /** Returns the index of the highest set bit in the array. - Should be accurate to within a few millisecs, depending on platform, - hardware, etc. + If the array is empty, this will return -1. */ - static int64 currentTimeMillis() throw(); + int getHighestBit() const throw(); - /** Returns the number of millisecs since system startup. + /** Converts the array to a number string. - Should be accurate to within a few millisecs, depending on platform, - hardware, etc. + Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). - @see getApproximateMillisecondCounter + If minuimumNumCharacters is greater than 0, the returned string will be + padded with leading zeros to reach at least that length. */ - static uint32 getMillisecondCounter() throw(); + const String toString (const int base, const int minimumNumCharacters = 1) const throw(); - /** Returns the number of millisecs since system startup. + /** Converts a number string to an array. - Same as getMillisecondCounter(), but returns a more accurate value, using - the high-res timer. + Any non-valid characters will be ignored. - @see getMillisecondCounter + Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). */ - static double getMillisecondCounterHiRes() throw(); + void parseString (const String& text, + const int base) throw(); - /** Waits until the getMillisecondCounter() reaches a given value. + /** Turns the array into a block of binary data. - This will make the thread sleep as efficiently as it can while it's waiting. + The data is arranged as little-endian, so the first byte of data is the low 8 bits + of the array, and so on. + + @see loadFromMemoryBlock */ - static void waitForMillisecondCounter (const uint32 targetTime) throw(); + const MemoryBlock toMemoryBlock() const throw(); - /** Less-accurate but faster version of getMillisecondCounter(). + /** Copies a block of raw data onto this array. - This will return the last value that getMillisecondCounter() returned, so doesn't - need to make a system call, but is less accurate - it shouldn't be more than - 100ms away from the correct time, though, so is still accurate enough for a - lot of purposes. + The data is arranged as little-endian, so the first byte of data is the low 8 bits + of the array, and so on. - @see getMillisecondCounter + @see toMemoryBlock */ - static uint32 getApproximateMillisecondCounter() throw(); + void loadFromMemoryBlock (const MemoryBlock& data) throw(); - // High-resolution timers.. + juce_UseDebuggingNewOperator - /** Returns the current high-resolution counter's tick-count. +private: + void ensureSize (const int numVals) throw(); + HeapBlock values; + int numValues, highestBit; + bool negative; +}; - This is a similar idea to getMillisecondCounter(), but with a higher - resolution. +#endif // __JUCE_BITARRAY_JUCEHEADER__ +/********* End of inlined file: juce_BitArray.h *********/ - @see getHighResolutionTicksPerSecond, highResolutionTicksToSeconds, - secondsToHighResolutionTicks +#endif +#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ + +#endif +#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ + +#endif +#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ + +/********* Start of inlined file: juce_MemoryBlock.h *********/ +#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ +#define __JUCE_MEMORYBLOCK_JUCEHEADER__ + +/** + A class to hold a resizable block of raw data. + +*/ +class JUCE_API MemoryBlock +{ +public: + + /** Create an uninitialised block with 0 size. */ + MemoryBlock() throw(); + + /** Creates a memory block with a given initial size. + + @param initialSize the size of block to create + @param initialiseToZero whether to clear the memory or just leave it uninitialised */ - static int64 getHighResolutionTicks() throw(); + MemoryBlock (const int initialSize, + const bool initialiseToZero = false) throw(); - /** Returns the resolution of the high-resolution counter in ticks per second. + /** Creates a copy of another memory block. */ + MemoryBlock (const MemoryBlock& other) throw(); - @see getHighResolutionTicks, highResolutionTicksToSeconds, - secondsToHighResolutionTicks + /** Creates a memory block using a copy of a block of data. + + @param dataToInitialiseFrom some data to copy into this block + @param sizeInBytes how much space to use */ - static int64 getHighResolutionTicksPerSecond() throw(); + MemoryBlock (const void* const dataToInitialiseFrom, + const int sizeInBytes) throw(); - /** Converts a number of high-resolution ticks into seconds. + /** Destructor. */ + ~MemoryBlock() throw(); - @see getHighResolutionTicks, getHighResolutionTicksPerSecond, - secondsToHighResolutionTicks + /** Copies another memory block onto this one. + + This block will be resized and copied to exactly match the other one. */ - static double highResolutionTicksToSeconds (const int64 ticks) throw(); + const MemoryBlock& operator= (const MemoryBlock& other) throw(); - /** Converts a number seconds into high-resolution ticks. + /** Compares two memory blocks. - @see getHighResolutionTicks, getHighResolutionTicksPerSecond, - highResolutionTicksToSeconds + @returns true only if the two blocks are the same size and have identical contents. */ - static int64 secondsToHighResolutionTicks (const double seconds) throw(); + bool operator== (const MemoryBlock& other) const throw(); -private: + /** Compares two memory blocks. - int64 millisSinceEpoch; -}; + @returns true if the two blocks are different sizes or have different contents. + */ + bool operator!= (const MemoryBlock& other) const throw(); -#endif // __JUCE_TIME_JUCEHEADER__ -/********* End of inlined file: juce_Time.h *********/ + /** Returns a pointer to the data, casting it to any type of primitive data required. -/********* Start of inlined file: juce_StringArray.h *********/ -#ifndef __JUCE_STRINGARRAY_JUCEHEADER__ -#define __JUCE_STRINGARRAY_JUCEHEADER__ + Note that the pointer returned will probably become invalid when the + block is resized. + */ + template + operator DataType*() const throw() { return (DataType*) data; } -/********* Start of inlined file: juce_VoidArray.h *********/ -#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ -#define __JUCE_VOIDARRAY_JUCEHEADER__ + /** Returns a void pointer to the data. -/********* Start of inlined file: juce_Array.h *********/ -#ifndef __JUCE_ARRAY_JUCEHEADER__ -#define __JUCE_ARRAY_JUCEHEADER__ + Note that the pointer returned will probably become invalid when the + block is resized. + */ + void* getData() const throw() { return data; } -/** - Holds a list of primitive objects, such as ints, doubles, or pointers. + /** Returns a byte from the memory block. - Examples of arrays are: Array or Array + This returns a reference, so you can also use it to set a byte. + */ + char& operator[] (const int offset) const throw() { return data [offset]; } - Note that when holding pointers to objects, the array doesn't take any ownership - of the objects - for doing this, see the OwnedArray class or the ReferenceCountedArray class. + /** Returns the block's current allocated size, in bytes. */ + int getSize() const throw() { return size; } - If you're using a class or struct as the element type, it must be - capable of being copied or moved with a straightforward memcpy, rather than - needing construction and destruction code. + /** Resizes the memory block. - For holding lists of strings, use the specialised class StringArray. + This will try to keep as much of the block's current content as it can, + and can optionally be made to clear any new space that gets allocated at + the end of the block. - To make all the array's methods thread-safe, pass in "CriticalSection" as the templated - TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. + @param newSize the new desired size for the block + @param initialiseNewSpaceToZero if the block gets enlarged, this determines + whether to clear the new section or just leave it + uninitialised + @see ensureSize + */ + void setSize (const int newSize, + const bool initialiseNewSpaceToZero = false) throw(); - @see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection -*/ -template -class Array -{ -public: + /** Increases the block's size only if it's smaller than a given size. - /** Creates an empty array. + @param minimumSize if the block is already bigger than this size, no action + will be taken; otherwise it will be increased to this size + @param initialiseNewSpaceToZero if the block gets enlarged, this determines + whether to clear the new section or just leave it + uninitialised + @see setSize + */ + void ensureSize (const int minimumSize, + const bool initialiseNewSpaceToZero = false) throw(); - @param granularity this is the size of increment by which the internal storage - used by the array will grow. Only change it from the default if you know the - array is going to be very big and needs to be able to grow efficiently. + /** Fills the entire memory block with a repeated byte value. + + This is handy for clearing a block of memory to zero. */ - Array (const int granularity = juceDefaultArrayGranularity) throw() - : data (granularity), - numUsed (0) - { - } + void fillWith (const uint8 valueToUse) throw(); - /** Creates a copy of another array. - @param other the array to copy + /** Adds another block of data to the end of this one. + + This block's size will be increased accordingly. */ - Array (const Array& other) throw() - : data (other.data.granularity) - { - other.lockArray(); - numUsed = other.numUsed; - data.setAllocatedSize (other.numUsed); - memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); - other.unlockArray(); - } + void append (const void* const data, + const int numBytes) throw(); - /** Initalises from a null-terminated C array of values. + /** Copies data into this MemoryBlock from a memory address. - @param values the array to copy from + @param srcData the memory location of the data to copy into this block + @param destinationOffset the offset in this block at which the data being copied should begin + @param numBytes how much to copy in (if this goes beyond the size of the memory block, + it will be clipped so not to do anything nasty) */ - Array (const ElementType* values) throw() - : data (juceDefaultArrayGranularity), - numUsed (0) - { - while (*values != 0) - add (*values++); - } + void copyFrom (const void* srcData, + int destinationOffset, + int numBytes) throw(); - /** Initalises from a C array of values. + /** Copies data from this MemoryBlock to a memory address. - @param values the array to copy from - @param numValues the number of values in the array + @param destData the memory location to write to + @param sourceOffset the offset within this block from which the copied data will be read + @param numBytes how much to copy (if this extends beyond the limits of the memory block, + zeros will be used for that portion of the data) */ - Array (const ElementType* values, int numValues) throw() - : data (juceDefaultArrayGranularity), - numUsed (numValues) - { - data.setAllocatedSize (numValues); - memcpy (data.elements, values, numValues * sizeof (ElementType)); - } + void copyTo (void* destData, + int sourceOffset, + int numBytes) const throw(); - /** Destructor. */ - ~Array() throw() - { - } + /** Chops out a section of the block. - /** Copies another array. - @param other the array to copy + This will remove a section of the memory block and close the gap around it, + shifting any subsequent data downwards and reducing the size of the block. + + If the range specified goes beyond the size of the block, it will be clipped. */ - const Array & operator= (const Array & other) throw() - { - if (this != &other) - { - other.lockArray(); - lock.enter(); + void removeSection (int startByte, int numBytesToRemove) throw(); - data.granularity = other.data.granularity; - data.ensureAllocatedSize (other.size()); - numUsed = other.numUsed; - memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); - minimiseStorageOverheads(); + /** Attempts to parse the contents of the block as a zero-terminated string of 8-bit + characters in the system's default encoding. */ + const String toString() const throw(); - lock.exit(); - other.unlockArray(); - } + /** Parses a string of hexadecimal numbers and writes this data into the memory block. - return *this; - } + The block will be resized to the number of valid bytes read from the string. + Non-hex characters in the string will be ignored. - /** Compares this array to another one. - Two arrays are considered equal if they both contain the same set of - elements, in the same order. - @param other the other array to compare with + @see String::toHexString() */ - template - bool operator== (const OtherArrayType& other) const throw() - { - lock.enter(); + void loadFromHexString (const String& sourceHexString) throw(); - if (numUsed != other.numUsed) - { - lock.exit(); - return false; - } + /** Sets a number of bits in the memory block, treating it as a long binary sequence. */ + void setBitRange (int bitRangeStart, + int numBits, + int binaryNumberToApply) throw(); - for (int i = numUsed; --i >= 0;) - { - if (data.elements [i] != other.data.elements [i]) - { - lock.exit(); - return false; - } - } + /** Reads a number of bits from the memory block, treating it as one long binary sequence */ + int getBitRange (int bitRangeStart, + int numBitsToRead) const throw(); - lock.exit(); - return true; - } + /** Returns a string of characters that represent the binary contents of this block. - /** Compares this array to another one. - Two arrays are considered equal if they both contain the same set of - elements, in the same order. - @param other the other array to compare with + Uses a 64-bit encoding system to allow binary data to be turned into a string + of simple non-extended characters, e.g. for storage in XML. + + @see fromBase64Encoding */ - template - bool operator!= (const OtherArrayType& other) const throw() - { - return ! operator== (other); - } + const String toBase64Encoding() const throw(); - /** Removes all elements from the array. - This will remove all the elements, and free any storage that the array is - using. To clear the array without freeing the storage, use the clearQuick() - method instead. + /** Takes a string of encoded characters and turns it into binary data. - @see clearQuick + The string passed in must have been created by to64BitEncoding(), and this + block will be resized to recreate the original data block. + + @see toBase64Encoding */ - void clear() throw() + bool fromBase64Encoding (const String& encodedString) throw(); + + juce_UseDebuggingNewOperator + +private: + + HeapBlock data; + int size; +}; + +#endif // __JUCE_MEMORYBLOCK_JUCEHEADER__ +/********* End of inlined file: juce_MemoryBlock.h *********/ + +#endif +#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ + +/********* Start of inlined file: juce_OwnedArray.h *********/ +#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ +#define __JUCE_OWNEDARRAY_JUCEHEADER__ + +/** An array designed for holding objects. + + This holds a list of pointers to objects, and will automatically + delete the objects when they are removed from the array, or when the + array is itself deleted. + + Declare it in the form: OwnedArray + + ..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass()); + + After adding objects, they are 'owned' by the array and will be deleted when + removed or replaced. + + To make all the array's methods thread-safe, pass in "CriticalSection" as the templated + TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. + + @see Array, ReferenceCountedArray, StringArray, CriticalSection +*/ +template + +class OwnedArray +{ +public: + + /** Creates an empty array. + + @param granularity this is the size of increment by which the internal storage + used by the array will grow. Only change it from the default if you know the + array is going to be very big and needs to be able to grow efficiently. + */ + OwnedArray (const int granularity = juceDefaultArrayGranularity) throw() + : data (granularity), + numUsed (0) { - lock.enter(); - data.setAllocatedSize (0); - numUsed = 0; - lock.exit(); } - /** Removes all elements from the array without freeing the array's allocated storage. + /** Deletes the array and also deletes any objects inside it. - @see clear + To get rid of the array without deleting its objects, use its + clear (false) method before deleting it. */ - void clearQuick() throw() + ~OwnedArray() + { + clear (true); + } + + /** Clears the array, optionally deleting the objects inside it first. */ + void clear (const bool deleteObjects = true) { lock.enter(); + + if (deleteObjects) + { + while (numUsed > 0) + delete data.elements [--numUsed]; + } + + data.setAllocatedSize (0); numUsed = 0; lock.exit(); } - /** Returns the current number of elements in the array. + /** Returns the number of items currently in the array. + @see operator[] */ inline int size() const throw() { return numUsed; } - /** Returns one of the elements in the array. - If the index passed in is beyond the range of valid elements, this - will return zero. + /** Returns a pointer to the object at this index in the array. - If you're certain that the index will always be a valid element, you - can call getUnchecked() instead, which is faster. + If the index is out-of-range, this will return a null pointer, (and + it could be null anyway, because it's ok for the array to hold null + pointers as well as objects). - @param index the index of the element being requested (0 is the first element in the array) - @see getUnchecked, getFirst, getLast + @see getUnchecked */ - inline ElementType operator[] (const int index) const throw() + inline ObjectClass* operator[] (const int index) const throw() { lock.enter(); - const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) - ? data.elements [index] - : ElementType(); + ObjectClass* const result = (((unsigned int) index) < (unsigned int) numUsed) + ? data.elements [index] + : (ObjectClass*) 0; lock.exit(); return result; } - /** Returns one of the elements in the array, without checking the index passed in. - - Unlike the operator[] method, this will try to return an element without - checking that the index is within the bounds of the array, so should only - be used when you're confident that it will always be a valid index. + /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. - @param index the index of the element being requested (0 is the first element in the array) - @see operator[], getFirst, getLast + This is a faster and less safe version of operator[] which doesn't check the index passed in, so + it can be used when you're sure the index if always going to be legal. */ - inline ElementType getUnchecked (const int index) const throw() + inline ObjectClass* getUnchecked (const int index) const throw() { lock.enter(); jassert (((unsigned int) index) < (unsigned int) numUsed); - const ElementType result = data.elements [index]; + ObjectClass* const result = data.elements [index]; lock.exit(); return result; } - /** Returns a direct reference to one of the elements in the array, without checking the index passed in. - - This is like getUnchecked, but returns a direct reference to the element, so that - you can alter it directly. Obviously this can be dangerous, so only use it when - absolutely necessary. + /** Returns a pointer to the first object in the array. - @param index the index of the element being requested (0 is the first element in the array) - @see operator[], getFirst, getLast + This will return a null pointer if the array's empty. + @see getLast */ - inline ElementType& getReference (const int index) const throw() + inline ObjectClass* getFirst() const throw() { lock.enter(); - jassert (((unsigned int) index) < (unsigned int) numUsed); - ElementType& result = data.elements [index]; + ObjectClass* const result = (numUsed > 0) ? data.elements [0] + : (ObjectClass*) 0; lock.exit(); return result; } - /** Returns the first element in the array, or 0 if the array is empty. + /** Returns a pointer to the last object in the array. - @see operator[], getUnchecked, getLast + This will return a null pointer if the array's empty. + @see getFirst */ - inline ElementType getFirst() const throw() + inline ObjectClass* getLast() const throw() { lock.enter(); - const ElementType result = (numUsed > 0) ? data.elements [0] - : ElementType(); + ObjectClass* const result = (numUsed > 0) ? data.elements [numUsed - 1] + : (ObjectClass*) 0; lock.exit(); return result; } - /** Returns the last element in the array, or 0 if the array is empty. + /** Finds the index of an object which might be in the array. - @see operator[], getUnchecked, getFirst + @param objectToLookFor the object to look for + @returns the index at which the object was found, or -1 if it's not found */ - inline ElementType getLast() const throw() + int indexOf (const ObjectClass* const objectToLookFor) const throw() { + int result = -1; + lock.enter(); - const ElementType result = (numUsed > 0) ? data.elements [numUsed - 1] - : ElementType(); - lock.exit(); + ObjectClass* const* e = data.elements; + + for (int i = numUsed; --i >= 0;) + { + if (objectToLookFor == *e) + { + result = (int) (e - data.elements); + break; + } + ++e; + } + + lock.exit(); return result; } - /** Finds the index of the first element which matches the value passed in. - - This will search the array for the given object, and return the index - of its first occurrence. If the object isn't found, the method will return -1. - - @param elementToLookFor the value or object to look for - @returns the index of the object, or -1 if it's not found - */ - int indexOf (const ElementType elementToLookFor) const throw() - { - int result = -1; - - lock.enter(); - const ElementType* e = data.elements; - - for (int i = numUsed; --i >= 0;) - { - if (elementToLookFor == *e) - { - result = (int) (e - data.elements); - break; - } - - ++e; - } - - lock.exit(); - return result; - } - - /** Returns true if the array contains at least one occurrence of an object. + /** Returns true if the array contains a specified object. - @param elementToLookFor the value or object to look for - @returns true if the item is found + @param objectToLookFor the object to look for + @returns true if the object is in the array */ - bool contains (const ElementType elementToLookFor) const throw() + bool contains (const ObjectClass* const objectToLookFor) const throw() { lock.enter(); - const ElementType* e = data.elements; - int num = numUsed; + ObjectClass* const* e = data.elements; + int i = numUsed; - while (num >= 4) + while (i >= 4) { - if (*e == elementToLookFor - || *++e == elementToLookFor - || *++e == elementToLookFor - || *++e == elementToLookFor) + if (objectToLookFor == *e + || objectToLookFor == *++e + || objectToLookFor == *++e + || objectToLookFor == *++e) { lock.exit(); return true; } - num -= 4; + i -= 4; ++e; } - while (num > 0) + while (i > 0) { - if (elementToLookFor == *e) + if (objectToLookFor == *e) { lock.exit(); return true; } - --num; + --i; ++e; } @@ -4920,299 +5137,157 @@ public: return false; } - /** Appends a new element at the end of the array. - - @param newElement the new object to add to the array - @see set, insert, addIfNotAlreadyThere, addSorted, addArray - */ - void add (const ElementType newElement) throw() - { - lock.enter(); - data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = newElement; - lock.exit(); - } + /** Appends a new object to the end of the array. - /** Inserts a new element into the array at a given position. + Note that the this object will be deleted by the OwnedArray when it + is removed, so be careful not to delete it somewhere else. - If the index is less than 0 or greater than the size of the array, the - element will be added to the end of the array. - Otherwise, it will be inserted into the array, moving all the later elements - along to make room. + Also be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. - @param indexToInsertAt the index at which the new element should be - inserted (pass in -1 to add it to the end) - @param newElement the new object to add to the array - @see add, addSorted, set + @param newObject the new object to add to the array + @see set, insert, addIfNotAlreadyThere, addSorted */ - void insert (int indexToInsertAt, const ElementType newElement) throw() + void add (const ObjectClass* const newObject) throw() { lock.enter(); data.ensureAllocatedSize (numUsed + 1); - - if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) - { - ElementType* const insertPos = data.elements + indexToInsertAt; - const int numberToMove = numUsed - indexToInsertAt; - - if (numberToMove > 0) - memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); - - *insertPos = newElement; - ++numUsed; - } - else - { - data.elements [numUsed++] = newElement; - } - + data.elements [numUsed++] = const_cast (newObject); lock.exit(); } - /** Inserts multiple copies of an element into the array at a given position. + /** Inserts a new object into the array at the given index. + + Note that the this object will be deleted by the OwnedArray when it + is removed, so be careful not to delete it somewhere else. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. - @param indexToInsertAt the index at which the new element should be inserted - @param newElement the new object to add to the array - @param numberOfTimesToInsertIt how many copies of the value to insert - @see insert, add, addSorted, set + Be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. + + @param indexToInsertAt the index at which the new element should be inserted + @param newObject the new object to add to the array + @see add, addSorted, addIfNotAlreadyThere, set */ - void insertMultiple (int indexToInsertAt, const ElementType newElement, - int numberOfTimesToInsertIt) throw() + void insert (int indexToInsertAt, + const ObjectClass* const newObject) throw() { - if (numberOfTimesToInsertIt > 0) + if (indexToInsertAt >= 0) { lock.enter(); - data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt); - - if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) - { - ElementType* insertPos = data.elements + indexToInsertAt; - const int numberToMove = numUsed - indexToInsertAt; - - memmove (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove * sizeof (ElementType)); - numUsed += numberOfTimesToInsertIt; - - while (--numberOfTimesToInsertIt >= 0) - *insertPos++ = newElement; - } - else - { - while (--numberOfTimesToInsertIt >= 0) - data.elements [numUsed++] = newElement; - } - - lock.exit(); - } - } - - /** Inserts an array of values into this array at a given position. - If the index is less than 0 or greater than the size of the array, the - new elements will be added to the end of the array. - Otherwise, they will be inserted into the array, moving all the later elements - along to make room. + if (indexToInsertAt > numUsed) + indexToInsertAt = numUsed; - @param indexToInsertAt the index at which the first new element should be inserted - @param newElements the new values to add to the array - @param numberOfElements how many items are in the array - @see insert, add, addSorted, set - */ - void insertArray (int indexToInsertAt, - const ElementType* newElements, - int numberOfElements) throw() - { - if (numberOfElements > 0) - { - lock.enter(); - data.ensureAllocatedSize (numUsed + numberOfElements); + data.ensureAllocatedSize (numUsed + 1); - if (((unsigned int) indexToInsertAt) < (unsigned int) numUsed) - { - ElementType* insertPos = data.elements + indexToInsertAt; - const int numberToMove = numUsed - indexToInsertAt; + ObjectClass** const e = data.elements + indexToInsertAt; + const int numToMove = numUsed - indexToInsertAt; - memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType)); - numUsed += numberOfElements; + if (numToMove > 0) + memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); - while (--numberOfElements >= 0) - *insertPos++ = *newElements++; - } - else - { - while (--numberOfElements >= 0) - data.elements [numUsed++] = *newElements++; - } + *e = const_cast (newObject); + ++numUsed; lock.exit(); } + else + { + add (newObject); + } } - /** Appends a new element at the end of the array as long as the array doesn't + /** Appends a new object at the end of the array as long as the array doesn't already contain it. - If the array already contains an element that matches the one passed in, nothing - will be done. + If the array already contains a matching object, nothing will be done. - @param newElement the new object to add to the array + @param newObject the new object to add to the array */ - void addIfNotAlreadyThere (const ElementType newElement) throw() + void addIfNotAlreadyThere (const ObjectClass* const newObject) throw() { lock.enter(); - if (! contains (newElement)) - add (newElement); + if (! contains (newObject)) + add (newObject); lock.exit(); } - /** Replaces an element with a new value. + /** Replaces an object in the array with a different one. If the index is less than zero, this method does nothing. - If the index is beyond the end of the array, the item is added to the end of the array. + If the index is beyond the end of the array, the new object is added to the end of the array. - @param indexToChange the index whose value you want to change - @param newValue the new value to set for this index. - @see add, insert + Be careful not to add the same object to the array more than once, + as this will obviously cause deletion of dangling pointers. + + @param indexToChange the index whose value you want to change + @param newObject the new value to set for this index. + @param deleteOldElement whether to delete the object that's being replaced with the new one + @see add, insert, remove */ void set (const int indexToChange, - const ElementType newValue) throw() + const ObjectClass* const newObject, + const bool deleteOldElement = true) { - jassert (indexToChange >= 0); - if (indexToChange >= 0) { + ObjectClass* toDelete = 0; lock.enter(); if (indexToChange < numUsed) { - data.elements [indexToChange] = newValue; + if (deleteOldElement) + { + toDelete = data.elements [indexToChange]; + + if (toDelete == newObject) + toDelete = 0; + } + + data.elements [indexToChange] = const_cast (newObject); } else { data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = newValue; + data.elements [numUsed++] = const_cast (newObject); } lock.exit(); - } - } - - /** Replaces an element with a new value without doing any bounds-checking. - - This just sets a value directly in the array's internal storage, so you'd - better make sure it's in range! - - @param indexToChange the index whose value you want to change - @param newValue the new value to set for this index. - @see set, getUnchecked - */ - void setUnchecked (const int indexToChange, - const ElementType newValue) throw() - { - lock.enter(); - jassert (((unsigned int) indexToChange) < (unsigned int) numUsed); - data.elements [indexToChange] = newValue; - lock.exit(); - } - - /** Adds elements from an array to the end of this array. - - @param elementsToAdd the array of elements to add - @param numElementsToAdd how many elements are in this other array - @see add - */ - void addArray (const ElementType* elementsToAdd, - int numElementsToAdd) throw() - { - lock.enter(); - - if (numElementsToAdd > 0) - { - data.ensureAllocatedSize (numUsed + numElementsToAdd); - - while (--numElementsToAdd >= 0) - data.elements [numUsed++] = *elementsToAdd++; - } - - lock.exit(); - } - - /** This swaps the contents of this array with those of another array. - - If you need to exchange two arrays, this is vastly quicker than using copy-by-value - because it just swaps their internal pointers. - */ - template - void swapWithArray (OtherArrayType& otherArray) throw() - { - lock.enter(); - otherArray.lock.enter(); - swapVariables (numUsed, otherArray.numUsed); - swapVariables (data.elements, otherArray.data.elements); - swapVariables (data.numAllocated, otherArray.data.numAllocated); - otherArray.lock.exit(); - lock.exit(); - } - - /** Adds elements from another array to the end of this array. - - @param arrayToAddFrom the array from which to copy the elements - @param startIndex the first element of the other array to start copying from - @param numElementsToAdd how many elements to add from the other array. If this - value is negative or greater than the number of available elements, - all available elements will be copied. - @see add - */ - template - void addArray (const OtherArrayType& arrayToAddFrom, - int startIndex = 0, - int numElementsToAdd = -1) throw() - { - arrayToAddFrom.lockArray(); - lock.enter(); - jassert (this != &arrayToAddFrom); - if (startIndex < 0) - { - jassertfalse - startIndex = 0; + delete toDelete; } - - if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) - numElementsToAdd = arrayToAddFrom.size() - startIndex; - - addArray ((const ElementType*) (arrayToAddFrom.data.elements + startIndex), numElementsToAdd); - - lock.exit(); - arrayToAddFrom.unlockArray(); } - /** Inserts a new element into the array, assuming that the array is sorted. + /** Inserts a new object into the array assuming that the array is sorted. - This will use a comparator to find the position at which the new element + This will use a comparator to find the position at which the new object should go. If the array isn't sorted, the behaviour of this method will be unpredictable. - @param comparator the comparator to use to compare the elements - see the sort() - method for details about the form this object should take - @param newElement the new element to insert to the array - @see add, sort + @param comparator the comparator to use to compare the elements - see the sort method + for details about this object's structure + @param newObject the new object to insert to the array + @see add, sort, indexOfSorted */ template void addSorted (ElementComparator& comparator, - const ElementType newElement) throw() + ObjectClass* const newObject) throw() { + (void) comparator; // if you pass in an object with a static compareElements() method, this + // avoids getting warning messages about the parameter being unused lock.enter(); - insert (findInsertIndexInSortedArray (comparator, data.elements, newElement, 0, numUsed), newElement); + insert (findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed), newObject); lock.exit(); } - /** Finds the index of an element in the array, assuming that the array is sorted. + /** Finds the index of an object in the array, assuming that the array is sorted. This will use a comparator to do a binary-chop to find the index of the given element, if it exists. If the array isn't sorted, the behaviour of this @@ -5220,13 +5295,13 @@ public: @param comparator the comparator to use to compare the elements - see the sort() method for details about the form this object should take - @param elementToLookFor the element to search for + @param objectToLookFor the object to search for @returns the index of the element, or -1 if it's not found @see addSorted, sort */ template int indexOfSorted (ElementComparator& comparator, - const ElementType elementToLookFor) const throw() + const ObjectClass* const objectToLookFor) const throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused @@ -5242,7 +5317,7 @@ public: lock.exit(); return -1; } - else if (comparator.compareElements (elementToLookFor, data.elements [start]) == 0) + else if (comparator.compareElements (objectToLookFor, data.elements [start]) == 0) { lock.exit(); return start; @@ -5256,7 +5331,7 @@ public: lock.exit(); return -1; } - else if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) + else if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0) start = halfway; else end = halfway; @@ -5264,62 +5339,63 @@ public: } } - /** Removes an element from the array. + /** Removes an object from the array. - This will remove the element at a given index, and move back - all the subsequent elements to close the gap. + This will remove the object at a given index (optionally also + deleting it) and move back all the subsequent objects to close the gap. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove - @returns the element that has been removed - @see removeValue, removeRange + @param deleteObject whether to delete the object that is removed + @see removeObject, removeRange */ - ElementType remove (const int indexToRemove) throw() + void remove (const int indexToRemove, + const bool deleteObject = true) { lock.enter(); + ObjectClass* toDelete = 0; if (((unsigned int) indexToRemove) < (unsigned int) numUsed) { - --numUsed; + ObjectClass** const e = data.elements + indexToRemove; - ElementType* const e = data.elements + indexToRemove; - ElementType const removed = *e; - const int numberToShift = numUsed - indexToRemove; + if (deleteObject) + toDelete = *e; - if (numberToShift > 0) - memmove (e, e + 1, numberToShift * sizeof (ElementType)); + --numUsed; + const int numToShift = numUsed - indexToRemove; + + if (numToShift > 0) + memmove (e, e + 1, numToShift * sizeof (ObjectClass*)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); - - lock.exit(); - return removed; - } - else - { - lock.exit(); - return ElementType(); } + + lock.exit(); + + delete toDelete; } - /** Removes an item from the array. + /** Removes a specified object from the array. - This will remove the first occurrence of the given element from the array. If the item isn't found, no action is taken. - @param valueToRemove the object to try to remove + @param objectToRemove the object to try to remove + @param deleteObject whether to delete the object (if it's found) @see remove, removeRange */ - void removeValue (const ElementType valueToRemove) throw() + void removeObject (const ObjectClass* const objectToRemove, + const bool deleteObject = true) { lock.enter(); - ElementType* e = data.elements; + ObjectClass** e = data.elements; for (int i = numUsed; --i >= 0;) { - if (valueToRemove == *e) + if (objectToRemove == *e) { - remove ((int) (e - data.elements)); + remove ((int) (e - data.elements), deleteObject); break; } @@ -5329,20 +5405,22 @@ public: lock.exit(); } - /** Removes a range of elements from the array. + /** Removes a range of objects from the array. - This will remove a set of elements, starting from the given index, - and move subsequent elements down to close the gap. + This will remove a set of objects, starting from the given index, + and move any subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. - @param startIndex the index of the first element to remove - @param numberToRemove how many elements should be removed - @see remove, removeValue + @param startIndex the index of the first object to remove + @param numberToRemove how many objects should be removed + @param deleteObjects whether to delete the objects that get removed + @see remove, removeObject */ void removeRange (int startIndex, - const int numberToRemove) throw() + const int numberToRemove, + const bool deleteObjects = true) { lock.enter(); const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); @@ -5350,8 +5428,17 @@ public: if (endIndex > startIndex) { + if (deleteObjects) + { + for (int i = startIndex; i < endIndex; ++i) + { + delete data.elements [i]; + data.elements [i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) + } + } + const int rangeSize = endIndex - startIndex; - ElementType* e = data.elements + startIndex; + ObjectClass** e = data.elements + startIndex; int numToShift = numUsed - endIndex; numUsed -= rangeSize; @@ -5368,118 +5455,62 @@ public: lock.exit(); } - /** Removes the last n elements from the array. - - @param howManyToRemove how many elements to remove from the end of the array - @see remove, removeValue, removeRange - */ - void removeLast (const int howManyToRemove = 1) throw() - { - lock.enter(); - numUsed = jmax (0, numUsed - howManyToRemove); - - if ((numUsed << 1) < data.numAllocated) - minimiseStorageOverheads(); - - lock.exit(); - } - - /** Removes any elements which are also in another array. + /** Removes the last n objects from the array. - @param otherArray the other array in which to look for elements to remove - @see removeValuesNotIn, remove, removeValue, removeRange + @param howManyToRemove how many objects to remove from the end of the array + @param deleteObjects whether to also delete the objects that are removed + @see remove, removeObject, removeRange */ - template - void removeValuesIn (const OtherArrayType& otherArray) throw() + void removeLast (int howManyToRemove = 1, + const bool deleteObjects = true) { - otherArray.lockArray(); lock.enter(); - if (this == &otherArray) + if (howManyToRemove >= numUsed) { - clear(); + clear (deleteObjects); } else { - if (otherArray.size() > 0) - { - for (int i = numUsed; --i >= 0;) - if (otherArray.contains (data.elements [i])) - remove (i); - } + while (--howManyToRemove >= 0) + remove (numUsed - 1, deleteObjects); } lock.exit(); - otherArray.unlockArray(); } - /** Removes any elements which are not found in another array. - - Only elements which occur in this other array will be retained. + /** Swaps a pair of objects in the array. - @param otherArray the array in which to look for elements NOT to remove - @see removeValuesIn, remove, removeValue, removeRange + If either of the indexes passed in is out-of-range, nothing will happen, + otherwise the two objects at these positions will be exchanged. */ - template - void removeValuesNotIn (const OtherArrayType& otherArray) throw() + void swap (const int index1, + const int index2) throw() { - otherArray.lockArray(); lock.enter(); - if (this != &otherArray) + if (((unsigned int) index1) < (unsigned int) numUsed + && ((unsigned int) index2) < (unsigned int) numUsed) { - if (otherArray.size() <= 0) - { - clear(); - } - else - { - for (int i = numUsed; --i >= 0;) - if (! otherArray.contains (data.elements [i])) - remove (i); - } + swapVariables (data.elements [index1], + data.elements [index2]); } lock.exit(); - otherArray.unlockArray(); } - /** Swaps over two elements in the array. + /** Moves one of the objects to a different position. - This swaps over the elements found at the two indexes passed in. - If either index is out-of-range, this method will do nothing. - - @param index1 index of one of the elements to swap - @param index2 index of the other element to swap - */ - void swap (const int index1, - const int index2) throw() - { - lock.enter(); - - if (((unsigned int) index1) < (unsigned int) numUsed - && ((unsigned int) index2) < (unsigned int) numUsed) - { - swapVariables (data.elements [index1], - data.elements [index2]); - } - - lock.exit(); - } - - /** Moves one of the values to a different position. - - This will move the value to a specified index, shuffling along + This will move the object to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. - @param currentIndex the index of the value to be moved. If this isn't a + @param currentIndex the index of the object to be moved. If this isn't a valid index, then nothing will be done - @param newIndex the index at which you'd like this value to end up. If this - is less than zero, the value will be moved to the end - of the array + @param newIndex the index at which you'd like this object to end up. If this + is less than zero, it will be moved to the end of the array */ void move (const int currentIndex, int newIndex) throw() @@ -5493,19 +5524,19 @@ public: if (((unsigned int) newIndex) >= (unsigned int) numUsed) newIndex = numUsed - 1; - const ElementType value = data.elements [currentIndex]; + ObjectClass* const value = data.elements [currentIndex]; if (newIndex > currentIndex) { memmove (data.elements + currentIndex, data.elements + currentIndex + 1, - (newIndex - currentIndex) * sizeof (ElementType)); + (newIndex - currentIndex) * sizeof (ObjectClass*)); } else { memmove (data.elements + newIndex + 1, data.elements + newIndex, - (currentIndex - newIndex) * sizeof (ElementType)); + (currentIndex - newIndex) * sizeof (ObjectClass*)); } data.elements [newIndex] = value; @@ -5515,6 +5546,23 @@ public: } } + /** This swaps the contents of this array with those of another array. + + If you need to exchange two arrays, this is vastly quicker than using copy-by-value + because it just swaps their internal pointers. + */ + template + void swapWithArray (OtherArrayType& otherArray) throw() + { + lock.enter(); + otherArray.lock.enter(); + swapVariables (numUsed, otherArray.numUsed); + swapVariables (data.elements, otherArray.data.elements); + swapVariables (data.numAllocated, otherArray.data.numAllocated); + otherArray.lock.exit(); + lock.exit(); + } + /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after @@ -5574,8 +5622,7 @@ public: be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. - - @see addSorted, indexOfSorted, sortArray + @see sortArray, indexOfSorted */ template void sort (ElementComparator& comparator, @@ -5583,6 +5630,7 @@ public: { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused + lock.enter(); sortArray (comparator, data.elements, 0, size() - 1, retainOrderOfEquivalentItems); lock.exit(); @@ -5615,24 +5663,32 @@ public: juce_UseDebuggingNewOperator private: - ArrayAllocationBase data; + ArrayAllocationBase data; int numUsed; TypeOfCriticalSectionToUse lock; + + // disallow copy constructor and assignment + OwnedArray (const OwnedArray&); + const OwnedArray& operator= (const OwnedArray&); }; -#endif // __JUCE_ARRAY_JUCEHEADER__ -/********* End of inlined file: juce_Array.h *********/ +#endif // __JUCE_OWNEDARRAY_JUCEHEADER__ +/********* End of inlined file: juce_OwnedArray.h *********/ -/** - A typedef for an Array of void*'s. +#endif +#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ - VoidArrays are used in various places throughout the library instead of - more strongly-typed arrays, to keep code-size low. -*/ -typedef Array VoidArray; +/********* Start of inlined file: juce_PropertySet.h *********/ +#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ +#define __JUCE_PROPERTYSET_JUCEHEADER__ -#endif // __JUCE_VOIDARRAY_JUCEHEADER__ -/********* End of inlined file: juce_VoidArray.h *********/ +/********* Start of inlined file: juce_StringPairArray.h *********/ +#ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ +#define __JUCE_STRINGPAIRARRAY_JUCEHEADER__ + +/********* Start of inlined file: juce_StringArray.h *********/ +#ifndef __JUCE_STRINGARRAY_JUCEHEADER__ +#define __JUCE_STRINGARRAY_JUCEHEADER__ #ifndef DOXYGEN // (used in StringArray::appendNumbersToDuplicates) @@ -5919,7770 +5975,7369 @@ public: juce_UseDebuggingNewOperator private: - VoidArray strings; + OwnedArray strings; }; #endif // __JUCE_STRINGARRAY_JUCEHEADER__ /********* End of inlined file: juce_StringArray.h *********/ -/********* Start of inlined file: juce_MemoryBlock.h *********/ -#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ -#define __JUCE_MEMORYBLOCK_JUCEHEADER__ - /** - A class to hold a resizable block of raw data. + A container for holding a set of strings which are keyed by another string. + @see StringArray */ -class JUCE_API MemoryBlock +class JUCE_API StringPairArray { public: - /** Create an uninitialised block with 0 size. */ - MemoryBlock() throw(); - - /** Creates a memory block with a given initial size. - - @param initialSize the size of block to create - @param initialiseToZero whether to clear the memory or just leave it uninitialised - */ - MemoryBlock (const int initialSize, - const bool initialiseToZero = false) throw(); - - /** Creates a copy of another memory block. */ - MemoryBlock (const MemoryBlock& other) throw(); - - /** Creates a memory block using a copy of a block of data. + /** Creates an empty array */ + StringPairArray (const bool ignoreCaseWhenComparingKeys = true) throw(); - @param dataToInitialiseFrom some data to copy into this block - @param sizeInBytes how much space to use - */ - MemoryBlock (const void* const dataToInitialiseFrom, - const int sizeInBytes) throw(); + /** Creates a copy of another array */ + StringPairArray (const StringPairArray& other) throw(); /** Destructor. */ - ~MemoryBlock() throw(); + ~StringPairArray() throw(); - /** Copies another memory block onto this one. + /** Copies the contents of another string array into this one */ + const StringPairArray& operator= (const StringPairArray& other) throw(); - This block will be resized and copied to exactly match the other one. - */ - const MemoryBlock& operator= (const MemoryBlock& other) throw(); + /** Compares two arrays. - /** Compares two memory blocks. + Comparisons are case-sensitive. - @returns true only if the two blocks are the same size and have identical contents. + @returns true only if the other array contains exactly the same strings with the same keys */ - bool operator== (const MemoryBlock& other) const throw(); - - /** Compares two memory blocks. + bool operator== (const StringPairArray& other) const throw(); - @returns true if the two blocks are different sizes or have different contents. - */ - bool operator!= (const MemoryBlock& other) const throw(); + /** Compares two arrays. - /** Returns a pointer to the data, casting it to any type of primitive data required. + Comparisons are case-sensitive. - Note that the pointer returned will probably become invalid when the - block is resized. + @returns false if the other array contains exactly the same strings with the same keys */ - template - operator DataType*() const throw() { return (DataType*) data; } + bool operator!= (const StringPairArray& other) const throw(); - /** Returns a void pointer to the data. + /** Finds the value corresponding to a key string. - Note that the pointer returned will probably become invalid when the - block is resized. - */ - void* getData() const throw() { return data; } + If no such key is found, this will just return an empty string. To check whether + a given key actually exists (because it might actually be paired with an empty string), use + the getAllKeys() method to obtain a list. - /** Returns a byte from the memory block. + Obviously the reference returned shouldn't be stored for later use, as the + string it refers to may disappear when the array changes. - This returns a reference, so you can also use it to set a byte. + @see getValue */ - char& operator[] (const int offset) const throw() { return data [offset]; } - - /** Returns the block's current allocated size, in bytes. */ - int getSize() const throw() { return size; } - - /** Resizes the memory block. - - This will try to keep as much of the block's current content as it can, - and can optionally be made to clear any new space that gets allocated at - the end of the block. + const String& operator[] (const String& key) const throw(); - @param newSize the new desired size for the block - @param initialiseNewSpaceToZero if the block gets enlarged, this determines - whether to clear the new section or just leave it - uninitialised - @see ensureSize - */ - void setSize (const int newSize, - const bool initialiseNewSpaceToZero = false) throw(); + /** Finds the value corresponding to a key string. - /** Increases the block's size only if it's smaller than a given size. + If no such key is found, this will just return the value provided as a default. - @param minimumSize if the block is already bigger than this size, no action - will be taken; otherwise it will be increased to this size - @param initialiseNewSpaceToZero if the block gets enlarged, this determines - whether to clear the new section or just leave it - uninitialised - @see setSize + @see operator[] */ - void ensureSize (const int minimumSize, - const bool initialiseNewSpaceToZero = false) throw(); - - /** Fills the entire memory block with a repeated byte value. + const String getValue (const String& key, const String& defaultReturnValue) const; - This is handy for clearing a block of memory to zero. - */ - void fillWith (const uint8 valueToUse) throw(); + /** Returns a list of all keys in the array. */ + const StringArray& getAllKeys() const throw() { return keys; } - /** Adds another block of data to the end of this one. + /** Returns a list of all values in the array. */ + const StringArray& getAllValues() const throw() { return values; } - This block's size will be increased accordingly. - */ - void append (const void* const data, - const int numBytes) throw(); + /** Returns the number of strings in the array */ + inline int size() const throw() { return keys.size(); }; - /** Copies data into this MemoryBlock from a memory address. + /** Adds or amends a key/value pair. - @param srcData the memory location of the data to copy into this block - @param destinationOffset the offset in this block at which the data being copied should begin - @param numBytes how much to copy in (if this goes beyond the size of the memory block, - it will be clipped so not to do anything nasty) + If a value already exists with this key, its value will be overwritten, + otherwise the key/value pair will be added to the array. */ - void copyFrom (const void* srcData, - int destinationOffset, - int numBytes) throw(); + void set (const String& key, + const String& value) throw(); - /** Copies data from this MemoryBlock to a memory address. + /** Adds the items from another array to this one. - @param destData the memory location to write to - @param sourceOffset the offset within this block from which the copied data will be read - @param numBytes how much to copy (if this extends beyond the limits of the memory block, - zeros will be used for that portion of the data) + This is equivalent to using set() to add each of the pairs from the other array. */ - void copyTo (void* destData, - int sourceOffset, - int numBytes) const throw(); + void addArray (const StringPairArray& other); - /** Chops out a section of the block. + /** Removes all elements from the array. */ + void clear() throw(); - This will remove a section of the memory block and close the gap around it, - shifting any subsequent data downwards and reducing the size of the block. + /** Removes a string from the array based on its key. - If the range specified goes beyond the size of the block, it will be clipped. + If the key isn't found, nothing will happen. */ - void removeSection (int startByte, int numBytesToRemove) throw(); - - /** Attempts to parse the contents of the block as a zero-terminated string of 8-bit - characters in the system's default encoding. */ - const String toString() const throw(); - - /** Parses a string of hexadecimal numbers and writes this data into the memory block. + void remove (const String& key) throw(); - The block will be resized to the number of valid bytes read from the string. - Non-hex characters in the string will be ignored. + /** Removes a string from the array based on its index. - @see String::toHexString() + If the index is out-of-range, no action will be taken. */ - void loadFromHexString (const String& sourceHexString) throw(); - - /** Sets a number of bits in the memory block, treating it as a long binary sequence. */ - void setBitRange (int bitRangeStart, - int numBits, - int binaryNumberToApply) throw(); - - /** Reads a number of bits from the memory block, treating it as one long binary sequence */ - int getBitRange (int bitRangeStart, - int numBitsToRead) const throw(); + void remove (const int index) throw(); - /** Returns a string of characters that represent the binary contents of this block. + /** Indicates whether to use a case-insensitive search when looking up a key string. + */ + void setIgnoresCase (const bool shouldIgnoreCase) throw(); - Uses a 64-bit encoding system to allow binary data to be turned into a string - of simple non-extended characters, e.g. for storage in XML. + /** Returns a descriptive string containing the items. - @see fromBase64Encoding + This is handy for dumping the contents of an array. */ - const String toBase64Encoding() const throw(); - - /** Takes a string of encoded characters and turns it into binary data. + const String getDescription() const; - The string passed in must have been created by to64BitEncoding(), and this - block will be resized to recreate the original data block. + /** Reduces the amount of storage being used by the array. - @see toBase64Encoding + Arrays typically allocate slightly more storage than they need, and after + removing elements, they may have quite a lot of unused space allocated. + This method will reduce the amount of allocated storage to a minimum. */ - bool fromBase64Encoding (const String& encodedString) throw(); + void minimiseStorageOverheads() throw(); juce_UseDebuggingNewOperator private: - - char* data; - int size; + StringArray keys, values; + bool ignoreCase; }; -#endif // __JUCE_MEMORYBLOCK_JUCEHEADER__ -/********* End of inlined file: juce_MemoryBlock.h *********/ +#endif // __JUCE_STRINGPAIRARRAY_JUCEHEADER__ +/********* End of inlined file: juce_StringPairArray.h *********/ -class FileInputStream; -class FileOutputStream; +/********* Start of inlined file: juce_XmlElement.h *********/ +#ifndef __JUCE_XMLELEMENT_JUCEHEADER__ +#define __JUCE_XMLELEMENT_JUCEHEADER__ -/** - Represents a local file or directory. +/********* Start of inlined file: juce_OutputStream.h *********/ +#ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ +#define __JUCE_OUTPUTSTREAM_JUCEHEADER__ - This class encapsulates the absolute pathname of a file or directory, and - has methods for finding out about the file and changing its properties. +/********* Start of inlined file: juce_InputStream.h *********/ +#ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ +#define __JUCE_INPUTSTREAM_JUCEHEADER__ - To read or write to the file, there are methods for returning an input or - output stream. +/** The base class for streams that read data. - @see FileInputStream, FileOutputStream + Input and output streams are used throughout the library - subclasses can override + some or all of the virtual functions to implement their behaviour. + + @see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream */ -class JUCE_API File +class JUCE_API InputStream { public: + /** Destructor. */ + virtual ~InputStream() {} - /** Creates an (invalid) file object. + /** Returns the total number of bytes available for reading in this stream. - The file is initially set to an empty path, so getFullPath() will return - an empty string, and comparing the file to File::nonexistent will return - true. + Note that this is the number of bytes available from the start of the + stream, not from the current position. - You can use its operator= method to point it at a proper file. + If the size of the stream isn't actually known, this may return -1. */ - File() throw() {} + virtual int64 getTotalLength() = 0; - /** Creates a file from an absolute path. + /** Returns true if the stream has no more data to read. */ + virtual bool isExhausted() = 0; - If the path supplied is a relative path, it is taken to be relative - to the current working directory (see File::getCurrentWorkingDirectory()), - but this isn't a recommended way of creating a file, because you - never know what the CWD is going to be. + /** Reads a set of bytes from the stream into a memory buffer. - On the Mac/Linux, the path can include "~" notation for referring to - user home directories. - */ - File (const String& path) throw(); + This is the only read method that subclasses actually need to implement, as the + InputStream base class implements the other read methods in terms of this one (although + it's often more efficient for subclasses to implement them directly). - /** Creates a copy of another file object. */ - File (const File& other) throw(); + @param destBuffer the destination buffer for the data + @param maxBytesToRead the maximum number of bytes to read - make sure the + memory block passed in is big enough to contain this + many bytes. - /** Destructor. */ - ~File() throw() {} + @returns the actual number of bytes that were read, which may be less than + maxBytesToRead if the stream is exhausted before it gets that far + */ + virtual int read (void* destBuffer, + int maxBytesToRead) = 0; - /** Sets the file based on an absolute pathname. + /** Reads a byte from the stream. - If the path supplied is a relative path, it is taken to be relative - to the current working directory (see File::getCurrentWorkingDirectory()), - but this isn't a recommended way of creating a file, because you - never know what the CWD is going to be. + If the stream is exhausted, this will return zero. - On the Mac/Linux, the path can include "~" notation for referring to - user home directories. + @see OutputStream::writeByte */ - const File& operator= (const String& newFilePath) throw(); + virtual char readByte(); - /** Copies from another file object. */ - const File& operator= (const File& otherFile) throw(); + /** Reads a boolean from the stream. - /** This static constant is used for referring to an 'invalid' file. */ - static const File nonexistent; + The bool is encoded as a single byte - 1 for true, 0 for false. - /** Checks whether the file actually exists. + If the stream is exhausted, this will return false. - @returns true if the file exists, either as a file or a directory. - @see existsAsFile, isDirectory + @see OutputStream::writeBool */ - bool exists() const throw(); + virtual bool readBool(); - /** Checks whether the file exists and is a file rather than a directory. + /** Reads two bytes from the stream as a little-endian 16-bit value. - @returns true only if this is a real file, false if it's a directory - or doesn't exist - @see exists, isDirectory - */ - bool existsAsFile() const throw(); + If the next two bytes read are byte1 and byte2, this returns + (byte1 | (byte2 << 8)). - /** Checks whether the file is a directory that exists. + If the stream is exhausted partway through reading the bytes, this will return zero. - @returns true only if the file is a directory which actually exists, so - false if it's a file or doesn't exist at all - @see exists, existsAsFile + @see OutputStream::writeShort, readShortBigEndian */ - bool isDirectory() const throw(); + virtual short readShort(); - /** Returns the size of the file in bytes. + /** Reads two bytes from the stream as a little-endian 16-bit value. - @returns the number of bytes in the file, or 0 if it doesn't exist. - */ - int64 getSize() const throw(); + If the next two bytes read are byte1 and byte2, this returns + (byte2 | (byte1 << 8)). - /** Utility function to convert a file size in bytes to a neat string description. + If the stream is exhausted partway through reading the bytes, this will return zero. - So for example 100 would return "100 bytes", 2000 would return "2 KB", - 2000000 would produce "2 MB", etc. + @see OutputStream::writeShortBigEndian, readShort */ - static const String descriptionOfSizeInBytes (const int64 bytes); + virtual short readShortBigEndian(); - /** Returns the complete, absolute path of this file. + /** Reads four bytes from the stream as a little-endian 32-bit value. - This includes the filename and all its parent folders. On Windows it'll - also include the drive letter prefix; on Mac or Linux it'll be a complete - path starting from the root folder. + If the next four bytes are byte1 to byte4, this returns + (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)). - If you just want the file's name, you should use getFileName() or - getFileNameWithoutExtension(). + If the stream is exhausted partway through reading the bytes, this will return zero. - @see getFileName, getRelativePathFrom + @see OutputStream::writeInt, readIntBigEndian */ - const String& getFullPathName() const throw() { return fullPath; } - - /** Returns the last section of the pathname. + virtual int readInt(); - Returns just the final part of the path - e.g. if the whole path - is "/moose/fish/foo.txt" this will return "foo.txt". + /** Reads four bytes from the stream as a big-endian 32-bit value. - For a directory, it returns the final part of the path - e.g. for the - directory "/moose/fish" it'll return "fish". + If the next four bytes are byte1 to byte4, this returns + (byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)). - If the filename begins with a dot, it'll return the whole filename, e.g. for - "/moose/.fish", it'll return ".fish" + If the stream is exhausted partway through reading the bytes, this will return zero. - @see getFullPathName, getFileNameWithoutExtension + @see OutputStream::writeIntBigEndian, readInt */ - const String getFileName() const throw(); + virtual int readIntBigEndian(); - /** Creates a relative path that refers to a file relatively to a given directory. + /** Reads eight bytes from the stream as a little-endian 64-bit value. - e.g. File ("/moose/foo.txt").getRelativePathFrom ("/moose/fish/haddock") - would return "../../foo.txt". + If the next eight bytes are byte1 to byte8, this returns + (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24) | (byte5 << 32) | (byte6 << 40) | (byte7 << 48) | (byte8 << 56)). - If it's not possible to navigate from one file to the other, an absolute - path is returned. If the paths are invalid, an empty string may also be - returned. + If the stream is exhausted partway through reading the bytes, this will return zero. - @param directoryToBeRelativeTo the directory which the resultant string will - be relative to. If this is actually a file rather than - a directory, its parent directory will be used instead. - If it doesn't exist, it's assumed to be a directory. - @see getChildFile, isAbsolutePath + @see OutputStream::writeInt64, readInt64BigEndian */ - const String getRelativePathFrom (const File& directoryToBeRelativeTo) const throw(); + virtual int64 readInt64(); - /** Returns the file's extension. + /** Reads eight bytes from the stream as a big-endian 64-bit value. - Returns the file extension of this file, also including the dot. + If the next eight bytes are byte1 to byte8, this returns + (byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | (byte3 << 40) | (byte2 << 48) | (byte1 << 56)). - e.g. "/moose/fish/foo.txt" would return ".txt" + If the stream is exhausted partway through reading the bytes, this will return zero. - @see hasFileExtension, withFileExtension, getFileNameWithoutExtension + @see OutputStream::writeInt64BigEndian, readInt64 */ - const String getFileExtension() const throw(); + virtual int64 readInt64BigEndian(); - /** Checks whether the file has a given extension. + /** Reads four bytes as a 32-bit floating point value. - @param extensionToTest the extension to look for - it doesn't matter whether or - not this string has a dot at the start, so ".wav" and "wav" - will have the same effect. The comparison used is - case-insensitve. + The raw 32-bit encoding of the float is read from the stream as a little-endian int. - @see getFileExtension, withFileExtension, getFileNameWithoutExtension + If the stream is exhausted partway through reading the bytes, this will return zero. + + @see OutputStream::writeFloat, readDouble */ - bool hasFileExtension (const String& extensionToTest) const throw(); + virtual float readFloat(); - /** Returns a version of this file with a different file extension. + /** Reads four bytes as a 32-bit floating point value. - e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html" + The raw 32-bit encoding of the float is read from the stream as a big-endian int. - @param newExtension the new extension, either with or without a dot at the start (this - doesn't make any difference). To get remove a file's extension altogether, - pass an empty string into this function. + If the stream is exhausted partway through reading the bytes, this will return zero. - @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension + @see OutputStream::writeFloatBigEndian, readDoubleBigEndian */ - const File withFileExtension (const String& newExtension) const throw(); + virtual float readFloatBigEndian(); - /** Returns the last part of the filename, without its file extension. + /** Reads eight bytes as a 64-bit floating point value. - e.g. for "/moose/fish/foo.txt" this will return "foo". + The raw 64-bit encoding of the double is read from the stream as a little-endian int64. - @see getFileName, getFileExtension, hasFileExtension, withFileExtension - */ - const String getFileNameWithoutExtension() const throw(); + If the stream is exhausted partway through reading the bytes, this will return zero. - /** Returns a 32-bit hash-code that identifies this file. - - This is based on the filename. Obviously it's possible, although unlikely, that - two files will have the same hash-code. + @see OutputStream::writeDouble, readFloat */ - int hashCode() const throw(); + virtual double readDouble(); - /** Returns a 64-bit hash-code that identifies this file. + /** Reads eight bytes as a 64-bit floating point value. - This is based on the filename. Obviously it's possible, although unlikely, that - two files will have the same hash-code. + The raw 64-bit encoding of the double is read from the stream as a big-endian int64. + + If the stream is exhausted partway through reading the bytes, this will return zero. + + @see OutputStream::writeDoubleBigEndian, readFloatBigEndian */ - int64 hashCode64() const throw(); + virtual double readDoubleBigEndian(); - /** Returns a file based on a relative path. + /** Reads an encoded 32-bit number from the stream using a space-saving compressed format. - This will find a child file or directory of the current object. + For small values, this is more space-efficient than using readInt() and OutputStream::writeInt() - e.g. - File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt". - File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt". + The format used is: number of significant bytes + up to 4 bytes in little-endian order. - If the string is actually an absolute path, it will be treated as such, e.g. - File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt" + @see OutputStream::writeCompressedInt() + */ + virtual int readCompressedInt(); - @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf + /** Reads a UTF8 string from the stream, up to the next linefeed or carriage return. + + This will read up to the next "\n" or "\r\n" or end-of-stream. + + After this call, the stream's position will be left pointing to the next character + following the line-feed, but the linefeeds aren't included in the string that + is returned. */ - const File getChildFile (String relativePath) const throw(); + virtual const String readNextLine(); - /** Returns a file which is in the same directory as this one. + /** Reads a zero-terminated UTF8 string from the stream. - This is equivalent to getParentDirectory().getChildFile (name). + This will read characters from the stream until it hits a zero character or + end-of-stream. - @see getChildFile, getParentDirectory + @see OutputStream::writeString, readEntireStreamAsString */ - const File getSiblingFile (const String& siblingFileName) const throw(); + virtual const String readString(); - /** Returns the directory that contains this file or directory. + /** Tries to read the whole stream and turn it into a string. - e.g. for "/moose/fish/foo.txt" this will return "/moose/fish". + This will read from the stream's current position until the end-of-stream, and + will try to make an educated guess about whether it's unicode or an 8-bit encoding. */ - const File getParentDirectory() const throw(); + virtual const String readEntireStreamAsString(); - /** Checks whether a file is somewhere inside a directory. + /** Reads from the stream and appends the data to a MemoryBlock. - Returns true if this file is somewhere inside a subdirectory of the directory - that is passed in. Neither file actually has to exist, because the function - just checks the paths for similarities. + @param destBlock the block to append the data onto + @param maxNumBytesToRead if this is a positive value, it sets a limit to the number + of bytes that will be read - if it's negative, data + will be read until the stream is exhausted. + @returns the number of bytes that were added to the memory block + */ + virtual int readIntoMemoryBlock (MemoryBlock& destBlock, + int maxNumBytesToRead = -1); - e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true. - File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true. + /** Returns the offset of the next byte that will be read from the stream. + + @see setPosition */ - bool isAChildOf (const File& potentialParentDirectory) const throw(); + virtual int64 getPosition() = 0; - /** Chooses a filename relative to this one that doesn't already exist. + /** Tries to move the current read position of the stream. - If this file is a directory, this will return a child file of this - directory that doesn't exist, by adding numbers to a prefix and suffix until - it finds one that isn't already there. + The position is an absolute number of bytes from the stream's start. - If the prefix + the suffix doesn't exist, it won't bother adding a number. + Some streams might not be able to do this, in which case they should do + nothing and return false. Others might be able to manage it by resetting + themselves and skipping to the correct position, although this is + obviously a bit slow. - e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might - return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt". + @returns true if the stream manages to reposition itself correctly + @see getPosition + */ + virtual bool setPosition (int64 newPosition) = 0; - @param prefix the string to use for the filename before the number - @param suffix the string to add to the filename after the number - @param putNumbersInBrackets if true, this will create filenames in the - format "prefix(number)suffix", if false, it will leave the - brackets out. + /** Reads and discards a number of bytes from the stream. + + Some input streams might implement this efficiently, but the base + class will just keep reading data until the requisite number of bytes + have been done. */ - const File getNonexistentChildFile (const String& prefix, - const String& suffix, - bool putNumbersInBrackets = true) const throw(); + virtual void skipNextBytes (int64 numBytesToSkip); - /** Chooses a filename for a sibling file to this one that doesn't already exist. + juce_UseDebuggingNewOperator - If this file doesn't exist, this will just return itself, otherwise it - will return an appropriate sibling that doesn't exist, e.g. if a file - "/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt". +protected: - @param putNumbersInBrackets whether to add brackets around the numbers that - get appended to the new filename. - */ - const File getNonexistentSibling (const bool putNumbersInBrackets = true) const throw(); + InputStream() throw() {} +}; - /** Compares the pathnames for two files. */ - bool operator== (const File& otherFile) const throw(); - /** Compares the pathnames for two files. */ - bool operator!= (const File& otherFile) const throw(); +#endif // __JUCE_INPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_InputStream.h *********/ - /** Checks whether a file can be created or written to. +/** + The base class for streams that write data to some kind of destination. - @returns true if it's possible to create and write to this file. If the file - doesn't already exist, this will check its parent directory to - see if writing is allowed. - @see setReadOnly - */ - bool hasWriteAccess() const throw(); + Input and output streams are used throughout the library - subclasses can override + some or all of the virtual functions to implement their behaviour. - /** Changes the write-permission of a file or directory. + @see InputStream, MemoryOutputStream, FileOutputStream +*/ +class JUCE_API OutputStream +{ +public: + /** Destructor. - @param shouldBeReadOnly whether to add or remove write-permission - @param applyRecursively if the file is a directory and this is true, it will - recurse through all the subfolders changing the permissions - of all files - @returns true if it manages to change the file's permissions. - @see hasWriteAccess + Some subclasses might want to do things like call flush() during their + destructors. */ - bool setReadOnly (const bool shouldBeReadOnly, - const bool applyRecursively = false) const throw(); + virtual ~OutputStream(); - /** Returns true if this file is a hidden or system file. + /** If the stream is using a buffer, this will ensure it gets written + out to the destination. */ + virtual void flush() = 0; - The criteria for deciding whether a file is hidden are platform-dependent. - */ - bool isHidden() const throw(); + /** Tries to move the stream's output position. - /** If this file is a link, this returns the file that it points to. + Not all streams will be able to seek to a new position - this will return + false if it fails to work. - If this file isn't actually link, it'll just return itself. + @see getPosition */ - const File getLinkedTarget() const throw(); + virtual bool setPosition (int64 newPosition) = 0; - /** Returns the last modification time of this file. + /** Returns the stream's current position. - @returns the time, or an invalid time if the file doesn't exist. - @see setLastModificationTime, getLastAccessTime, getCreationTime + @see setPosition */ - const Time getLastModificationTime() const throw(); + virtual int64 getPosition() = 0; - /** Returns the last time this file was accessed. + /** Writes a block of data to the stream. - @returns the time, or an invalid time if the file doesn't exist. - @see setLastAccessTime, getLastModificationTime, getCreationTime + When creating a subclass of OutputStream, this is the only write method + that needs to be overloaded - the base class has methods for writing other + types of data which use this to do the work. + + @returns false if the write operation fails for some reason */ - const Time getLastAccessTime() const throw(); + virtual bool write (const void* dataToWrite, + int howManyBytes) = 0; - /** Returns the time that this file was created. + /** Writes a single byte to the stream. - @returns the time, or an invalid time if the file doesn't exist. - @see getLastModificationTime, getLastAccessTime + @see InputStream::readByte */ - const Time getCreationTime() const throw(); + virtual void writeByte (char byte); - /** Changes the modification time for this file. + /** Writes a boolean to the stream. - @param newTime the time to apply to the file - @returns true if it manages to change the file's time. - @see getLastModificationTime, setLastAccessTime, setCreationTime + This is encoded as a byte - either 1 or 0. + + @see InputStream::readBool */ - bool setLastModificationTime (const Time& newTime) const throw(); + virtual void writeBool (bool boolValue); - /** Changes the last-access time for this file. + /** Writes a 16-bit integer to the stream in a little-endian byte order. - @param newTime the time to apply to the file - @returns true if it manages to change the file's time. - @see getLastAccessTime, setLastModificationTime, setCreationTime + This will write two bytes to the stream: (value & 0xff), then (value >> 8). + + @see InputStream::readShort */ - bool setLastAccessTime (const Time& newTime) const throw(); + virtual void writeShort (short value); - /** Changes the creation date for this file. + /** Writes a 16-bit integer to the stream in a big-endian byte order. - @param newTime the time to apply to the file - @returns true if it manages to change the file's time. - @see getCreationTime, setLastModificationTime, setLastAccessTime + This will write two bytes to the stream: (value >> 8), then (value & 0xff). + + @see InputStream::readShortBigEndian */ - bool setCreationTime (const Time& newTime) const throw(); + virtual void writeShortBigEndian (short value); - /** If possible, this will try to create a version string for the given file. + /** Writes a 32-bit integer to the stream in a little-endian byte order. - The OS may be able to look at the file and give a version for it - e.g. with - executables, bundles, dlls, etc. If no version is available, this will - return an empty string. + @see InputStream::readInt */ - const String getVersion() const throw(); + virtual void writeInt (int value); - /** Creates an empty file if it doesn't already exist. + /** Writes a 32-bit integer to the stream in a big-endian byte order. - If the file that this object refers to doesn't exist, this will create a file - of zero size. + @see InputStream::readIntBigEndian + */ + virtual void writeIntBigEndian (int value); - If it already exists or is a directory, this method will do nothing. + /** Writes a 64-bit integer to the stream in a little-endian byte order. - @returns true if the file has been created (or if it already existed). - @see createDirectory + @see InputStream::readInt64 */ - bool create() const throw(); - - /** Creates a new directory for this filename. + virtual void writeInt64 (int64 value); - This will try to create the file as a directory, and fill also create - any parent directories it needs in order to complete the operation. + /** Writes a 64-bit integer to the stream in a big-endian byte order. - @returns true if the directory has been created successfully, (or if it - already existed beforehand). - @see create + @see InputStream::readInt64BigEndian */ - bool createDirectory() const throw(); + virtual void writeInt64BigEndian (int64 value); - /** Deletes a file. + /** Writes a 32-bit floating point value to the stream. - If this file is actually a directory, it may not be deleted correctly if it - contains files. See deleteRecursively() as a better way of deleting directories. + The binary 32-bit encoding of the float is written as a little-endian int. - @returns true if the file has been successfully deleted (or if it didn't exist to - begin with). - @see deleteRecursively + @see InputStream::readFloat */ - bool deleteFile() const throw(); + virtual void writeFloat (float value); - /** Deletes a file or directory and all its subdirectories. + /** Writes a 32-bit floating point value to the stream. - If this file is a directory, this will try to delete it and all its subfolders. If - it's just a file, it will just try to delete the file. + The binary 32-bit encoding of the float is written as a big-endian int. - @returns true if the file and all its subfolders have been successfully deleted - (or if it didn't exist to begin with). - @see deleteFile + @see InputStream::readFloatBigEndian */ - bool deleteRecursively() const throw(); + virtual void writeFloatBigEndian (float value); - /** Moves this file or folder to the trash. + /** Writes a 64-bit floating point value to the stream. - @returns true if the operation succeeded. It could fail if the trash is full, or - if the file is write-protected, so you should check the return value - and act appropriately. - */ - bool moveToTrash() const throw(); + The eight raw bytes of the double value are written out as a little-endian 64-bit int. - /** Moves or renames a file. + @see InputStream::readDouble + */ + virtual void writeDouble (double value); - Tries to move a file to a different location. - If the target file already exists, this will attempt to delete it first, and - will fail if this can't be done. + /** Writes a 64-bit floating point value to the stream. - Note that the destination file isn't the directory to put it in, it's the actual - filename that you want the new file to have. + The eight raw bytes of the double value are written out as a big-endian 64-bit int. - @returns true if the operation succeeds + @see InputStream::readDoubleBigEndian */ - bool moveFileTo (const File& targetLocation) const throw(); + virtual void writeDoubleBigEndian (double value); - /** Copies a file. + /** Writes a condensed encoding of a 32-bit integer. - Tries to copy a file to a different location. - If the target file already exists, this will attempt to delete it first, and - will fail if this can't be done. + If you're storing a lot of integers which are unlikely to have very large values, + this can save a lot of space, because values under 0xff will only take up 2 bytes, + under 0xffff only 3 bytes, etc. - @returns true if the operation succeeds + The format used is: number of significant bytes + up to 4 bytes in little-endian order. + + @see InputStream::readCompressedInt */ - bool copyFileTo (const File& targetLocation) const throw(); + virtual void writeCompressedInt (int value); - /** Copies a directory. + /** Stores a string in the stream. - Tries to copy an entire directory, recursively. + This isn't the method to use if you're trying to append text to the end of a + text-file! It's intended for storing a string for later retrieval + by InputStream::readString. - If this file isn't a directory or if any target files can't be created, this - will return false. + It writes the string to the stream as UTF8, with a null character terminating it. - @param newDirectory the directory that this one should be copied to. Note that this - is the name of the actual directory to create, not the directory - into which the new one should be placed, so there must be enough - write privileges to create it if it doesn't exist. Any files inside - it will be overwritten by similarly named ones that are copied. - */ - bool copyDirectoryTo (const File& newDirectory) const throw(); + For appending text to a file, instead use writeText, printf, or operator<< - /** Used in file searching, to specify whether to return files, directories, or both. + @see InputStream::readString, writeText, printf, operator<< */ - enum TypesOfFileToFind - { - findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */ - findFiles = 2, /**< Use this flag to indicate that you want to find files. */ - findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */ - ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */ - }; - - /** Searches inside a directory for files matching a wildcard pattern. + virtual void writeString (const String& text); - Assuming that this file is a directory, this method will search it - for either files or subdirectories whose names match a filename pattern. + /** Writes a string of text to the stream. - @param results an array to which File objects will be added for the - files that the search comes up with - @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to - return files, directories, or both. If the ignoreHiddenFiles flag - is also added to this value, hidden files won't be returned - @param searchRecursively if true, all subdirectories will be recursed into to do - an exhaustive search - @param wildCardPattern the filename pattern to search for, e.g. "*.txt" - @returns the number of results that have been found + It can either write it as 8-bit system-encoded characters, or as unicode, and + can also add unicode header bytes (0xff, 0xfe) to indicate the endianness (this + should only be done at the start of a file). - @see getNumberOfChildFiles, DirectoryIterator + The method also replaces '\\n' characters in the text with '\\r\\n'. */ - int findChildFiles (OwnedArray& results, - const int whatToLookFor, - const bool searchRecursively, - const String& wildCardPattern = JUCE_T("*")) const throw(); + virtual void writeText (const String& text, + const bool asUnicode, + const bool writeUnicodeHeaderBytes); - /** Searches inside a directory and counts how many files match a wildcard pattern. + /** Writes a string of text to the stream. - Assuming that this file is a directory, this method will search it - for either files or subdirectories whose names match a filename pattern, - and will return the number of matches found. + @see writeText + */ + virtual void printf (const char* format, ...); - This isn't a recursive call, and will only search this directory, not - its children. + /** Reads data from an input stream and writes it to this stream. - @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to - count files, directories, or both. If the ignoreHiddenFiles flag - is also added to this value, hidden files won't be counted - @param wildCardPattern the filename pattern to search for, e.g. "*.txt" - @returns the number of matches found - @see findChildFiles, DirectoryIterator + @param source the stream to read from + @param maxNumBytesToWrite the number of bytes to read from the stream (if this is + less than zero, it will keep reading until the input + is exhausted) */ - int getNumberOfChildFiles (const int whatToLookFor, - const String& wildCardPattern = JUCE_T("*")) const throw(); + virtual int writeFromInputStream (InputStream& source, + int maxNumBytesToWrite); - /** Returns true if this file is a directory that contains one or more subdirectories. - @see isDirectory, findChildFiles - */ - bool containsSubDirectories() const throw(); + /** Writes a number to the stream as 8-bit characters in the default system encoding. */ + virtual OutputStream& operator<< (const int number); - /** Creates a stream to read from this file. + /** Writes a number to the stream as 8-bit characters in the default system encoding. */ + virtual OutputStream& operator<< (const double number); - @returns a stream that will read from this file (initially positioned at the - start of the file), or 0 if the file can't be opened for some reason - @see createOutputStream, loadFileAsData - */ - FileInputStream* createInputStream() const throw(); + /** Writes a character to the stream. */ + virtual OutputStream& operator<< (const char character); - /** Creates a stream to write to this file. + /** Writes a null-terminated string to the stream. */ + virtual OutputStream& operator<< (const char* const text); - If the file exists, the stream that is returned will be positioned ready for - writing at the end of the file, so you might want to use deleteFile() first - to write to an empty file. + /** Writes a null-terminated unicode text string to the stream, converting it + to 8-bit characters in the default system encoding. */ + virtual OutputStream& operator<< (const juce_wchar* const text); - @returns a stream that will write to this file (initially positioned at the - end of the file), or 0 if the file can't be opened for some reason - @see createInputStream, printf, appendData, appendText - */ - FileOutputStream* createOutputStream (const int bufferSize = 0x8000) const throw(); + /** Writes a string to the stream as 8-bit characters in the default system encoding. */ + virtual OutputStream& operator<< (const String& text); - /** Loads a file's contents into memory as a block of binary data. + juce_UseDebuggingNewOperator - Of course, trying to load a very large file into memory will blow up, so - it's better to check first. +protected: - @param result the data block to which the file's contents should be appended - note - that if the memory block might already contain some data, you - might want to clear it first - @returns true if the file could all be read into memory - */ - bool loadFileAsData (MemoryBlock& result) const throw(); + OutputStream() throw(); +}; - /** Reads a file into memory as a string. +#endif // __JUCE_OUTPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_OutputStream.h *********/ - Attempts to load the entire file as a zero-terminated string. +/********* Start of inlined file: juce_File.h *********/ +#ifndef __JUCE_FILE_JUCEHEADER__ +#define __JUCE_FILE_JUCEHEADER__ - This makes use of InputStream::readEntireStreamAsString, which should - automatically cope with unicode/acsii file formats. - */ - const String loadFileAsString() const throw(); +/********* Start of inlined file: juce_Time.h *********/ +#ifndef __JUCE_TIME_JUCEHEADER__ +#define __JUCE_TIME_JUCEHEADER__ - /** Writes text to the end of the file. +/********* Start of inlined file: juce_RelativeTime.h *********/ +#ifndef __JUCE_RELATIVETIME_JUCEHEADER__ +#define __JUCE_RELATIVETIME_JUCEHEADER__ - This will try to do a printf to the file. +/** A relative measure of time. - @returns false if it can't write to the file for some reason - */ - bool printf (const tchar* format, ...) const throw(); + The time is stored as a number of seconds, at double-precision floating + point accuracy, and may be positive or negative. - /** Appends a block of binary data to the end of the file. + If you need an absolute time, (i.e. a date + time), see the Time class. +*/ +class JUCE_API RelativeTime +{ +public: - This will try to write the given buffer to the end of the file. + /** Creates a RelativeTime. - @returns false if it can't write to the file for some reason + @param seconds the number of seconds, which may be +ve or -ve. + @see milliseconds, minutes, hours, days, weeks */ - bool appendData (const void* const dataToAppend, - const int numberOfBytes) const throw(); + explicit RelativeTime (const double seconds = 0.0) throw(); - /** Replaces this file's contents with a given block of data. + /** Copies another relative time. */ + RelativeTime (const RelativeTime& other) throw(); - This will delete the file and replace it with the given data. + /** Copies another relative time. */ + const RelativeTime& operator= (const RelativeTime& other) throw(); - A nice feature of this method is that it's safe - instead of deleting - the file first and then re-writing it, it creates a new temporary file, - writes the data to that, and then moves the new file to replace the existing - file. This means that if the power gets pulled out or something crashes, - you're a lot less likely to end up with an empty file.. + /** Destructor. */ + ~RelativeTime() throw(); - Returns true if the operation succeeds, or false if it fails. + /** Creates a new RelativeTime object representing a number of milliseconds. - @see appendText + @see minutes, hours, days, weeks */ - bool replaceWithData (const void* const dataToWrite, - const int numberOfBytes) const throw(); - - /** Appends a string to the end of the file. + static const RelativeTime milliseconds (const int milliseconds) throw(); - This will try to append a text string to the file, as either 16-bit unicode - or 8-bit characters in the default system encoding. + /** Creates a new RelativeTime object representing a number of milliseconds. - It can also write the 'ff fe' unicode header bytes before the text to indicate - the endianness of the file. + @see minutes, hours, days, weeks + */ + static const RelativeTime milliseconds (const int64 milliseconds) throw(); - Any single \\n characters in the string are replaced with \\r\\n before it is written. + /** Creates a new RelativeTime object representing a number of minutes. - @see replaceWithText + @see milliseconds, hours, days, weeks */ - bool appendText (const String& textToAppend, - const bool asUnicode = false, - const bool writeUnicodeHeaderBytes = false) const throw(); - - /** Replaces this file's contents with a given text string. - - This will delete the file and replace it with the given text. + static const RelativeTime minutes (const double numberOfMinutes) throw(); - A nice feature of this method is that it's safe - instead of deleting - the file first and then re-writing it, it creates a new temporary file, - writes the text to that, and then moves the new file to replace the existing - file. This means that if the power gets pulled out or something crashes, - you're a lot less likely to end up with an empty file.. + /** Creates a new RelativeTime object representing a number of hours. - For an explanation of the parameters here, see the appendText() method. + @see milliseconds, minutes, days, weeks + */ + static const RelativeTime hours (const double numberOfHours) throw(); - Returns true if the operation succeeds, or false if it fails. + /** Creates a new RelativeTime object representing a number of days. - @see appendText + @see milliseconds, minutes, hours, weeks */ - bool replaceWithText (const String& textToWrite, - const bool asUnicode = false, - const bool writeUnicodeHeaderBytes = false) const throw(); + static const RelativeTime days (const double numberOfDays) throw(); - /** Creates a set of files to represent each file root. + /** Creates a new RelativeTime object representing a number of weeks. - e.g. on Windows this will create files for "c:\", "d:\" etc according - to which ones are available. On the Mac/Linux, this will probably - just add a single entry for "/". + @see milliseconds, minutes, hours, days */ - static void findFileSystemRoots (OwnedArray& results) throw(); + static const RelativeTime weeks (const double numberOfWeeks) throw(); - /** Finds the name of the drive on which this file lives. + /** Returns the number of milliseconds this time represents. - @returns the volume label of the drive, or an empty string if this isn't possible + @see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks */ - const String getVolumeLabel() const throw(); + int64 inMilliseconds() const throw(); - /** Returns the serial number of the volume on which this file lives. + /** Returns the number of seconds this time represents. - @returns the serial number, or zero if there's a problem doing this + @see inMilliseconds, inMinutes, inHours, inDays, inWeeks */ - int getVolumeSerialNumber() const throw(); + double inSeconds() const throw() { return seconds; } - /** Returns the number of bytes free on the drive that this file lives on. + /** Returns the number of minutes this time represents. - @returns the number of bytes free, or 0 if there's a problem finding this out - @see getVolumeTotalSize + @see inMilliseconds, inSeconds, inHours, inDays, inWeeks */ - int64 getBytesFreeOnVolume() const throw(); + double inMinutes() const throw(); - /** Returns the total size of the drive that contains this file. + /** Returns the number of hours this time represents. - @returns the total number of bytes that the volume can hold - @see getBytesFreeOnVolume + @see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks */ - int64 getVolumeTotalSize() const throw(); - - /** Returns true if this file is on a CD or DVD drive. */ - bool isOnCDRomDrive() const throw(); + double inHours() const throw(); - /** Returns true if this file is on a hard disk. + /** Returns the number of days this time represents. - This will fail if it's a network drive, but will still be true for - removable hard-disks. + @see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks */ - bool isOnHardDisk() const throw(); + double inDays() const throw(); - /** Returns true if this file is on a removable disk drive. + /** Returns the number of weeks this time represents. - This might be a usb-drive, a CD-rom, or maybe a network drive. + @see inMilliseconds, inSeconds, inMinutes, inHours, inDays */ - bool isOnRemovableDrive() const throw(); - - /** Launches the file as a process. + double inWeeks() const throw(); - - if the file is executable, this will run it. + /** Returns a readable textual description of the time. - - if it's a document of some kind, it will launch the document with its - default viewer application. + The exact format of the string returned will depend on + the magnitude of the time - e.g. - - if it's a folder, it will be opened in Explorer, Finder, or equivalent. + "1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms" - @see revealToUser - */ - bool startAsProcess (const String& parameters = String::empty) const throw(); + so that only the two most significant units are printed. - /** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location. - @see startAsProcess - */ - void revealToUser() const throw(); + The returnValueForZeroTime value is the result that is returned if the + length is zero. Depending on your application you might want to use this + to return something more relevant like "empty" or "0 secs", etc. - /** A set of types of location that can be passed to the getSpecialLocation() method. + @see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks */ - enum SpecialLocationType - { - /** The user's home folder. This is the same as using File ("~"). */ - userHomeDirectory, - - /** The user's default documents folder. On Windows, this might be the user's - "My Documents" folder. On the Mac it'll be their "Documents" folder. Linux - doesn't tend to have one of these, so it might just return their home folder. - */ - userDocumentsDirectory, + const String getDescription (const String& returnValueForZeroTime = JUCE_T("0")) const throw(); - /** The folder that contains the user's desktop objects. */ - userDesktopDirectory, + /** Compares two RelativeTimes. */ + bool operator== (const RelativeTime& other) const throw(); + /** Compares two RelativeTimes. */ + bool operator!= (const RelativeTime& other) const throw(); - /** The folder in which applications store their persistent user-specific settings. - On Windows, this might be "\Documents and Settings\username\Application Data". - On the Mac, it might be "~/Library". If you're going to store your settings in here, - always create your own sub-folder to put them in, to avoid making a mess. - */ - userApplicationDataDirectory, + /** Compares two RelativeTimes. */ + bool operator> (const RelativeTime& other) const throw(); + /** Compares two RelativeTimes. */ + bool operator< (const RelativeTime& other) const throw(); + /** Compares two RelativeTimes. */ + bool operator>= (const RelativeTime& other) const throw(); + /** Compares two RelativeTimes. */ + bool operator<= (const RelativeTime& other) const throw(); - /** An equivalent of the userApplicationDataDirectory folder that is shared by all users - of the computer, rather than just the current user. + /** Adds another RelativeTime to this one and returns the result. */ + const RelativeTime operator+ (const RelativeTime& timeToAdd) const throw(); + /** Subtracts another RelativeTime from this one and returns the result. */ + const RelativeTime operator- (const RelativeTime& timeToSubtract) const throw(); - On the Mac it'll be "/Library", on Windows, it could be something like - "\Documents and Settings\All Users\Application Data". + /** Adds a number of seconds to this RelativeTime and returns the result. */ + const RelativeTime operator+ (const double secondsToAdd) const throw(); + /** Subtracts a number of seconds from this RelativeTime and returns the result. */ + const RelativeTime operator- (const double secondsToSubtract) const throw(); - Depending on the setup, this folder may be read-only. - */ - commonApplicationDataDirectory, + /** Adds another RelativeTime to this one. */ + const RelativeTime& operator+= (const RelativeTime& timeToAdd) throw(); + /** Subtracts another RelativeTime from this one. */ + const RelativeTime& operator-= (const RelativeTime& timeToSubtract) throw(); - /** The folder that should be used for temporary files. + /** Adds a number of seconds to this time. */ + const RelativeTime& operator+= (const double secondsToAdd) throw(); - Always delete them when you're finished, to keep the user's computer tidy! - */ - tempDirectory, + /** Subtracts a number of seconds from this time. */ + const RelativeTime& operator-= (const double secondsToSubtract) throw(); - /** Returns this application's executable file. + juce_UseDebuggingNewOperator - If running as a plug-in or DLL, this will (where possible) be the DLL rather than the - host app. +private: + double seconds; +}; - On the mac this will return the unix binary, not the package folder - see - currentApplicationFile for that. +#endif // __JUCE_RELATIVETIME_JUCEHEADER__ +/********* End of inlined file: juce_RelativeTime.h *********/ - See also invokedExecutableFile, which is similar, but if the exe was launched from a - file link, invokedExecutableFile will return the name of the link. - */ - currentExecutableFile, +/** + Holds an absolute date and time. - /** Returns this application's location. + Internally, the time is stored at millisecond precision. - If running as a plug-in or DLL, this will (where possible) be the DLL rather than the - host app. + @see RelativeTime +*/ +class JUCE_API Time +{ +public: - On the mac this will return the package folder (if it's in one), not the unix binary - that's inside it - compare with currentExecutableFile. - */ - currentApplicationFile, + /** Creates a Time object. - /** Returns the file that was invoked to launch this executable. - This may differ from currentExecutableFile if the app was started from e.g. a link - this - will return the name of the link that was used, whereas currentExecutableFile will return - the actual location of the target executable. - */ - invokedExecutableFile, + This default constructor creates a time of 1st January 1970, (which is + represented internally as 0ms). - /** The directory in which applications normally get installed. + To create a time object representing the current time, use getCurrentTime(). - So on windows, this would be something like "c:\program files", on the - Mac "/Applications", or "/usr" on linux. - */ - globalApplicationsDirectory, + @see getCurrentTime + */ + Time() throw(); - /** The most likely place where a user might store their music files. - */ - userMusicDirectory, + /** Creates a copy of another Time object. */ + Time (const Time& other) throw(); - /** The most likely place where a user might store their movie files. - */ - userMoviesDirectory, - }; + /** Creates a time based on a number of milliseconds. - /** Finds the location of a special type of file or directory, such as a home folder or - documents folder. + The internal millisecond count is set to 0 (1st January 1970). To create a + time object set to the current time, use getCurrentTime(). - @see SpecialLocationType + @param millisecondsSinceEpoch the number of milliseconds since the unix + 'epoch' (midnight Jan 1st 1970). + @see getCurrentTime, currentTimeMillis */ - static const File JUCE_CALLTYPE getSpecialLocation (const SpecialLocationType type); + Time (const int64 millisecondsSinceEpoch) throw(); - /** Returns a temporary file in the system's temp directory. + /** Creates a time from a set of date components. - This will try to return the name of a non-existent temp file. + The timezone is assumed to be whatever the system is using as its locale. - To get the temp folder, you can use getSpecialLocation (File::tempDirectory). + @param year the year, in 4-digit format, e.g. 2004 + @param month the month, in the range 0 to 11 + @param day the day of the month, in the range 1 to 31 + @param hours hours in 24-hour clock format, 0 to 23 + @param minutes minutes 0 to 59 + @param seconds seconds 0 to 59 + @param milliseconds milliseconds 0 to 999 + @param useLocalTime if true, encode using the current machine's local time; if + false, it will always work in GMT. */ - static const File createTempFile (const String& fileNameEnding) throw(); - - /** Returns the current working directory. + Time (const int year, + const int month, + const int day, + const int hours, + const int minutes, + const int seconds = 0, + const int milliseconds = 0, + const bool useLocalTime = true) throw(); - @see setAsCurrentWorkingDirectory - */ - static const File getCurrentWorkingDirectory() throw(); + /** Destructor. */ + ~Time() throw(); - /** Sets the current working directory to be this file. + /** Copies this time from another one. */ + const Time& operator= (const Time& other) throw(); - For this to work the file must point to a valid directory. + /** Returns a Time object that is set to the current system time. - @returns true if the current directory has been changed. - @see getCurrentWorkingDirectory + @see currentTimeMillis */ - bool setAsCurrentWorkingDirectory() const throw(); + static const Time JUCE_CALLTYPE getCurrentTime() throw(); - /** The system-specific file separator character. + /** Returns the time as a number of milliseconds. - On Windows, this will be '\', on Mac/Linux, it'll be '/' + @returns the number of milliseconds this Time object represents, since + midnight jan 1st 1970. + @see getMilliseconds */ - static const tchar separator; + int64 toMilliseconds() const throw() { return millisSinceEpoch; } - /** The system-specific file separator character, as a string. + /** Returns the year. - On Windows, this will be '\', on Mac/Linux, it'll be '/' + A 4-digit format is used, e.g. 2004. */ - static const tchar* separatorString; + int getYear() const throw(); - /** Removes illegal characters from a filename. + /** Returns the number of the month. - This will return a copy of the given string after removing characters - that are not allowed in a legal filename, and possibly shortening the - string if it's too long. + The value returned is in the range 0 to 11. + @see getMonthName + */ + int getMonth() const throw(); - Because this will remove slashes, don't use it on an absolute pathname. + /** Returns the name of the month. - @see createLegalPathName + @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false + it'll return the long form, e.g. "January" + @see getMonth */ - static const String createLegalFileName (const String& fileNameToFix) throw(); - - /** Removes illegal characters from a pathname. + const String getMonthName (const bool threeLetterVersion) const throw(); - Similar to createLegalFileName(), but this won't remove slashes, so can - be used on a complete pathname. + /** Returns the day of the month. - @see createLegalFileName + The value returned is in the range 1 to 31. */ - static const String createLegalPathName (const String& pathNameToFix) throw(); + int getDayOfMonth() const throw(); - /** Indicates whether filenames are case-sensitive on the current operating system. - */ - static bool areFileNamesCaseSensitive(); + /** Returns the number of the day of the week. - /** Returns true if the string seems to be a fully-specified absolute path. + The value returned is in the range 0 to 6 (0 = sunday, 1 = monday, etc). */ - static bool isAbsolutePath (const String& path) throw(); - - juce_UseDebuggingNewOperator + int getDayOfWeek() const throw(); -private: + /** Returns the name of the weekday. - String fullPath; + @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if + false, it'll return the full version, e.g. "Tuesday". + */ + const String getWeekdayName (const bool threeLetterVersion) const throw(); - // internal way of contructing a file without checking the path - friend class DirectoryIterator; - File (const String&, int) throw(); - const String getPathUpToLastSlash() const throw(); -}; + /** Returns the number of hours since midnight. -#endif // __JUCE_FILE_JUCEHEADER__ -/********* End of inlined file: juce_File.h *********/ + This is in 24-hour clock format, in the range 0 to 23. -/** - A simple implemenation of a Logger that writes to a file. + @see getHoursInAmPmFormat, isAfternoon + */ + int getHours() const throw(); - @see Logger -*/ -class JUCE_API FileLogger : public Logger -{ -public: + /** Returns true if the time is in the afternoon. - /** Creates a FileLogger for a given file. + So it returns true for "PM", false for "AM". - @param fileToWriteTo the file that to use - new messages will be appended - to the file. If the file doesn't exist, it will be created, - along with any parent directories that are needed. - @param welcomeMessage when opened, the logger will write a header to the log, along - with the current date and time, and this welcome message - @param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists - but is larger than this number of bytes, then the start of the - file will be truncated to keep the size down. This prevents a log - file getting ridiculously large over time. The file will be truncated - at a new-line boundary. If this value is less than zero, no size limit - will be imposed; if it's zero, the file will always be deleted. Note that - the size is only checked once when this object is created - any logging - that is done later will be appended without any checking + @see getHoursInAmPmFormat, getHours */ - FileLogger (const File& fileToWriteTo, - const String& welcomeMessage, - const int maxInitialFileSizeBytes = 128 * 1024); + bool isAfternoon() const throw(); - /** Destructor. */ - ~FileLogger(); + /** Returns the hours in 12-hour clock format. - void logMessage (const String& message); + This will return a value 1 to 12 - use isAfternoon() to find out + whether this is in the afternoon or morning. - /** Helper function to create a log file in the correct place for this platform. + @see getHours, isAfternoon + */ + int getHoursInAmPmFormat() const throw(); - On Windows this will return a logger with a path such as: - c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName] + /** Returns the number of minutes, 0 to 59. */ + int getMinutes() const throw(); - On the Mac it'll create something like: - ~/Library/Logs/[logFileName] + /** Returns the number of seconds, 0 to 59. */ + int getSeconds() const throw(); - The method might return 0 if the file can't be created for some reason. + /** Returns the number of milliseconds, 0 to 999. - @param logFileSubDirectoryName if a subdirectory is needed, this is what it will be called - - it's best to use the something like the name of your application here. - @param logFileName the name of the file to create, e.g. "MyAppLog.txt". Don't just - call it "log.txt" because if it goes in a directory with logs - from other applications (as it will do on the Mac) then no-one - will know which one is yours! - @param welcomeMessage a message that will be written to the log when it's opened. - @param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this) - */ - static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName, - const String& logFileName, - const String& welcomeMessage, - const int maxInitialFileSizeBytes = 128 * 1024); + Unlike toMilliseconds(), this just returns the position within the + current second rather than the total number since the epoch. - juce_UseDebuggingNewOperator + @see toMilliseconds + */ + int getMilliseconds() const throw(); -private: - File logFile; - CriticalSection logLock; - FileOutputStream* logStream; + /** Returns true if the local timezone uses a daylight saving correction. */ + bool isDaylightSavingTime() const throw(); - void trimFileSize (int maxFileSizeBytes) const; + /** Returns a 3-character string to indicate the local timezone. */ + const String getTimeZone() const throw(); - FileLogger (const FileLogger&); - const FileLogger& operator= (const FileLogger&); -}; + /** Quick way of getting a string version of a date and time. -#endif // __JUCE_FILELOGGER_JUCEHEADER__ -/********* End of inlined file: juce_FileLogger.h *********/ + For a more powerful way of formatting the date and time, see the formatted() method. -#endif -#ifndef __JUCE_INITIALISATION_JUCEHEADER__ + @param includeDate whether to include the date in the string + @param includeTime whether to include the time in the string + @param includeSeconds if the time is being included, this provides an option not to include + the seconds in it + @param use24HourClock if the time is being included, sets whether to use am/pm or 24 + hour notation. + @see formatted + */ + const String toString (const bool includeDate, + const bool includeTime, + const bool includeSeconds = true, + const bool use24HourClock = false) const throw(); -/********* Start of inlined file: juce_Initialisation.h *********/ -#ifndef __JUCE_INITIALISATION_JUCEHEADER__ -#define __JUCE_INITIALISATION_JUCEHEADER__ + /** Converts this date/time to a string with a user-defined format. -/** Initialises Juce's GUI classes. + This uses the C strftime() function to format this time as a string. To save you + looking it up, these are the escape codes that strftime uses (other codes might + work on some platforms and not others, but these are the common ones): - If you're embedding Juce into an application that uses its own event-loop rather - than using the START_JUCE_APPLICATION macro, call this function before making any - Juce calls, to make sure things are initialised correctly. + %a is replaced by the locale's abbreviated weekday name. + %A is replaced by the locale's full weekday name. + %b is replaced by the locale's abbreviated month name. + %B is replaced by the locale's full month name. + %c is replaced by the locale's appropriate date and time representation. + %d is replaced by the day of the month as a decimal number [01,31]. + %H is replaced by the hour (24-hour clock) as a decimal number [00,23]. + %I is replaced by the hour (12-hour clock) as a decimal number [01,12]. + %j is replaced by the day of the year as a decimal number [001,366]. + %m is replaced by the month as a decimal number [01,12]. + %M is replaced by the minute as a decimal number [00,59]. + %p is replaced by the locale's equivalent of either a.m. or p.m. + %S is replaced by the second as a decimal number [00,61]. + %U is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. + %w is replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. + %W is replaced by the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. + %x is replaced by the locale's appropriate date representation. + %X is replaced by the locale's appropriate time representation. + %y is replaced by the year without century as a decimal number [00,99]. + %Y is replaced by the year with century as a decimal number. + %Z is replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. + %% is replaced by %. - Note that if you're creating a Juce DLL for Windows, you may also need to call the - PlatformUtilities::setCurrentModuleInstanceHandle() method. + @see toString + */ + const String formatted (const tchar* const format) const throw(); - @see shutdownJuce_GUI(), initialiseJuce_NonGUI() -*/ -void JUCE_PUBLIC_FUNCTION initialiseJuce_GUI(); + /** Adds a RelativeTime to this time and returns the result. */ + const Time operator+ (const RelativeTime& delta) const throw() { return Time (millisSinceEpoch + delta.inMilliseconds()); } -/** Clears up any static data being used by Juce's GUI classes. + /** Subtracts a RelativeTime from this time and returns the result. */ + const Time operator- (const RelativeTime& delta) const throw() { return Time (millisSinceEpoch - delta.inMilliseconds()); } - If you're embedding Juce into an application that uses its own event-loop rather - than using the START_JUCE_APPLICATION macro, call this function in your shutdown - code to clean up any juce objects that might be lying around. + /** Returns the relative time difference between this time and another one. */ + const RelativeTime operator- (const Time& other) const throw() { return RelativeTime::milliseconds (millisSinceEpoch - other.millisSinceEpoch); } - @see initialiseJuce_GUI(), initialiseJuce_NonGUI() -*/ -void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI(); + /** Compares two Time objects. */ + bool operator== (const Time& other) const throw() { return millisSinceEpoch == other.millisSinceEpoch; } -/** Initialises the core parts of Juce. + /** Compares two Time objects. */ + bool operator!= (const Time& other) const throw() { return millisSinceEpoch != other.millisSinceEpoch; } - If you're embedding Juce into either a command-line program, call this function - at the start of your main() function to make sure that Juce is initialised correctly. + /** Compares two Time objects. */ + bool operator< (const Time& other) const throw() { return millisSinceEpoch < other.millisSinceEpoch; } - Note that if you're creating a Juce DLL for Windows, you may also need to call the - PlatformUtilities::setCurrentModuleInstanceHandle() method. + /** Compares two Time objects. */ + bool operator<= (const Time& other) const throw() { return millisSinceEpoch <= other.millisSinceEpoch; } - @see shutdownJuce_NonGUI, initialiseJuce_GUI -*/ -void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI(); + /** Compares two Time objects. */ + bool operator> (const Time& other) const throw() { return millisSinceEpoch > other.millisSinceEpoch; } -/** Clears up any static data being used by Juce's non-gui core classes. + /** Compares two Time objects. */ + bool operator>= (const Time& other) const throw() { return millisSinceEpoch >= other.millisSinceEpoch; } - If you're embedding Juce into either a command-line program, call this function - at the end of your main() function if you want to make sure any Juce objects are - cleaned up correctly. + /** Tries to set the computer's clock. - @see initialiseJuce_NonGUI, initialiseJuce_GUI -*/ -void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); - -#endif // __JUCE_INITIALISATION_JUCEHEADER__ -/********* End of inlined file: juce_Initialisation.h *********/ - -#endif -#ifndef __JUCE_LOGGER_JUCEHEADER__ - -#endif -#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ - -/********* Start of inlined file: juce_PlatformUtilities.h *********/ -#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ -#define __JUCE_PLATFORMUTILITIES_JUCEHEADER__ - -/** - A collection of miscellaneous platform-specific utilities. - -*/ -class JUCE_API PlatformUtilities -{ -public: + @returns true if this succeeds, although depending on the system, the + application might not have sufficient privileges to do this. + */ + bool setSystemTimeToThisTime() const throw(); - /** Plays the operating system's default alert 'beep' sound. */ - static void beep(); + /** Returns the name of a day of the week. - static bool launchEmailWithAttachments (const String& targetEmailAddress, - const String& emailSubject, - const String& bodyText, - const StringArray& filesToAttach); + @param dayNumber the day, 0 to 6 (0 = sunday, 1 = monday, etc) + @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if + false, it'll return the full version, e.g. "Tuesday". + */ + static const String getWeekdayName (int dayNumber, + const bool threeLetterVersion) throw(); -#if JUCE_MAC || JUCE_IPHONE || DOXYGEN + /** Returns the name of one of the months. - /** MAC ONLY - Turns a Core CF String into a juce one. */ - static const String cfStringToJuceString (CFStringRef cfString); + @param monthNumber the month, 0 to 11 + @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false + it'll return the long form, e.g. "January" + */ + static const String getMonthName (int monthNumber, + const bool threeLetterVersion) throw(); - /** MAC ONLY - Turns a juce string into a Core CF one. */ - static CFStringRef juceStringToCFString (const String& s); + // Static methods for getting system timers directly.. - /** MAC ONLY - Turns a file path into an FSRef, returning true if it succeeds. */ - static bool makeFSRefFromPath (FSRef* destFSRef, const String& path); + /** Returns the current system time. - /** MAC ONLY - Turns an FSRef into a juce string path. */ - static const String makePathFromFSRef (FSRef* file); + Returns the number of milliseconds since midnight jan 1st 1970. - /** MAC ONLY - Converts any decomposed unicode characters in a string into - their precomposed equivalents. + Should be accurate to within a few millisecs, depending on platform, + hardware, etc. */ - static const String convertToPrecomposedUnicode (const String& s); - - /** MAC ONLY - Gets the type of a file from the file's resources. */ - static OSType getTypeOfFile (const String& filename); + static int64 currentTimeMillis() throw(); - /** MAC ONLY - Returns true if this file is actually a bundle. */ - static bool isBundle (const String& filename); + /** Returns the number of millisecs since system startup. - /** MAC ONLY - Adds an item to the dock */ - static void addItemToDock (const File& file); + Should be accurate to within a few millisecs, depending on platform, + hardware, etc. - /** MAC ONLY - Returns the current OS version number. - E.g. if it's running on 10.4, this will be 4, 10.5 will return 5, etc. + @see getApproximateMillisecondCounter */ - static int getOSXMinorVersionNumber() throw(); -#endif - -#if JUCE_WINDOWS || DOXYGEN + static uint32 getMillisecondCounter() throw(); - // Some registry helper functions: + /** Returns the number of millisecs since system startup. - /** WIN32 ONLY - Returns a string from the registry. + Same as getMillisecondCounter(), but returns a more accurate value, using + the high-res timer. - The path is a string for the entire path of a value in the registry, - e.g. "HKEY_CURRENT_USER\Software\foo\bar" + @see getMillisecondCounter */ - static const String getRegistryValue (const String& regValuePath, - const String& defaultValue = String::empty); + static double getMillisecondCounterHiRes() throw(); - /** WIN32 ONLY - Sets a registry value as a string. + /** Waits until the getMillisecondCounter() reaches a given value. - This will take care of creating any groups needed to get to the given - registry value. + This will make the thread sleep as efficiently as it can while it's waiting. */ - static void setRegistryValue (const String& regValuePath, - const String& value); - - /** WIN32 ONLY - Returns true if the given value exists in the registry. */ - static bool registryValueExists (const String& regValuePath); - - /** WIN32 ONLY - Deletes a registry value. */ - static void deleteRegistryValue (const String& regValuePath); + static void waitForMillisecondCounter (const uint32 targetTime) throw(); - /** WIN32 ONLY - Deletes a registry key (which is registry-talk for 'folder'). */ - static void deleteRegistryKey (const String& regKeyPath); + /** Less-accurate but faster version of getMillisecondCounter(). - /** WIN32 ONLY - Creates a file association in the registry. + This will return the last value that getMillisecondCounter() returned, so doesn't + need to make a system call, but is less accurate - it shouldn't be more than + 100ms away from the correct time, though, so is still accurate enough for a + lot of purposes. - This lets you set the exe that should be launched by a given file extension. - @param fileExtension the file extension to associate, including the - initial dot, e.g. ".txt" - @param symbolicDescription a space-free short token to identify the file type - @param fullDescription a human-readable description of the file type - @param targetExecutable the executable that should be launched - @param iconResourceNumber the icon that gets displayed for the file type will be - found by looking up this resource number in the - executable. Pass 0 here to not use an icon + @see getMillisecondCounter */ - static void registerFileAssociation (const String& fileExtension, - const String& symbolicDescription, - const String& fullDescription, - const File& targetExecutable, - int iconResourceNumber); - - /** WIN32 ONLY - This returns the HINSTANCE of the current module. + static uint32 getApproximateMillisecondCounter() throw(); - In a normal Juce application this will be set to the module handle - of the application executable. + // High-resolution timers.. - If you're writing a DLL using Juce and plan to use any Juce messaging or - windows, you'll need to make sure you use the setCurrentModuleInstanceHandle() - to set the correct module handle in your DllMain() function, because - the win32 system relies on the correct instance handle when opening windows. - */ - static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() throw(); + /** Returns the current high-resolution counter's tick-count. - /** WIN32 ONLY - Sets a new module handle to be used by the library. + This is a similar idea to getMillisecondCounter(), but with a higher + resolution. - @see getCurrentModuleInstanceHandle() + @see getHighResolutionTicksPerSecond, highResolutionTicksToSeconds, + secondsToHighResolutionTicks */ - static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) throw(); + static int64 getHighResolutionTicks() throw(); - /** WIN32 ONLY - Gets the command-line params as a string. + /** Returns the resolution of the high-resolution counter in ticks per second. - This is needed to avoid unicode problems with the argc type params. + @see getHighResolutionTicks, highResolutionTicksToSeconds, + secondsToHighResolutionTicks */ - static const String JUCE_CALLTYPE getCurrentCommandLineParams() throw(); -#endif + static int64 getHighResolutionTicksPerSecond() throw(); - /** Clears the floating point unit's flags. + /** Converts a number of high-resolution ticks into seconds. - Only has an effect under win32, currently. + @see getHighResolutionTicks, getHighResolutionTicksPerSecond, + secondsToHighResolutionTicks */ - static void fpuReset(); - -#if JUCE_LINUX || JUCE_WINDOWS + static double highResolutionTicksToSeconds (const int64 ticks) throw(); - /** Loads a dynamically-linked library into the process's address space. + /** Converts a number seconds into high-resolution ticks. - @param pathOrFilename the platform-dependent name and search path - @returns a handle which can be used by getProcedureEntryPoint(), or - zero if it fails. - @see freeDynamicLibrary, getProcedureEntryPoint + @see getHighResolutionTicks, getHighResolutionTicksPerSecond, + highResolutionTicksToSeconds */ - static void* loadDynamicLibrary (const String& pathOrFilename); + static int64 secondsToHighResolutionTicks (const double seconds) throw(); - /** Frees a dynamically-linked library. +private: - @param libraryHandle a handle created by loadDynamicLibrary - @see loadDynamicLibrary, getProcedureEntryPoint - */ - static void freeDynamicLibrary (void* libraryHandle); + int64 millisSinceEpoch; +}; - /** Finds a procedure call in a dynamically-linked library. +#endif // __JUCE_TIME_JUCEHEADER__ +/********* End of inlined file: juce_Time.h *********/ - @param libraryHandle a library handle returned by loadDynamicLibrary - @param procedureName the name of the procedure call to try to load - @returns a pointer to the function if found, or 0 if it fails - @see loadDynamicLibrary - */ - static void* getProcedureEntryPoint (void* libraryHandle, - const String& procedureName); -#endif +class FileInputStream; +class FileOutputStream; -#if JUCE_LINUX || DOXYGEN +/** + Represents a local file or directory. -#endif -}; + This class encapsulates the absolute pathname of a file or directory, and + has methods for finding out about the file and changing its properties. -#if JUCE_MAC || JUCE_IPHONE + To read or write to the file, there are methods for returning an input or + output stream. -/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object - using RAII. + @see FileInputStream, FileOutputStream */ -class ScopedAutoReleasePool +class JUCE_API File { public: - ScopedAutoReleasePool(); - ~ScopedAutoReleasePool(); -private: - void* pool; + /** Creates an (invalid) file object. - ScopedAutoReleasePool (const ScopedAutoReleasePool&); - const ScopedAutoReleasePool& operator= (const ScopedAutoReleasePool&); -}; + The file is initially set to an empty path, so getFullPath() will return + an empty string, and comparing the file to File::nonexistent will return + true. -#endif + You can use its operator= method to point it at a proper file. + */ + File() throw() {} -#if JUCE_MAC + /** Creates a file from an absolute path. -/** - A wrapper class for picking up events from an Apple IR remote control device. + If the path supplied is a relative path, it is taken to be relative + to the current working directory (see File::getCurrentWorkingDirectory()), + but this isn't a recommended way of creating a file, because you + never know what the CWD is going to be. - To use it, just create a subclass of this class, implementing the buttonPressed() - callback, then call start() and stop() to start or stop receiving events. -*/ -class JUCE_API AppleRemoteDevice -{ -public: + On the Mac/Linux, the path can include "~" notation for referring to + user home directories. + */ + File (const String& path) throw(); - AppleRemoteDevice(); - virtual ~AppleRemoteDevice(); + /** Creates a copy of another file object. */ + File (const File& other) throw(); - /** The set of buttons that may be pressed. - @see buttonPressed - */ - enum ButtonType - { - menuButton = 0, /**< The menu button (if it's held for a short time). */ - playButton, /**< The play button. */ - plusButton, /**< The plus or volume-up button. */ - minusButton, /**< The minus or volume-down button. */ - rightButton, /**< The right button (if it's held for a short time). */ - leftButton, /**< The left button (if it's held for a short time). */ - rightButton_Long, /**< The right button (if it's held for a long time). */ - leftButton_Long, /**< The menu button (if it's held for a long time). */ - menuButton_Long, /**< The menu button (if it's held for a long time). */ - playButtonSleepMode, - switched - }; + /** Destructor. */ + ~File() throw() {} - /** Override this method to receive the callback about a button press. + /** Sets the file based on an absolute pathname. - The callback will happen on the application's message thread. + If the path supplied is a relative path, it is taken to be relative + to the current working directory (see File::getCurrentWorkingDirectory()), + but this isn't a recommended way of creating a file, because you + never know what the CWD is going to be. - Some buttons trigger matching up and down events, in which the isDown parameter - will be true and then false. Others only send a single event when the - button is pressed. + On the Mac/Linux, the path can include "~" notation for referring to + user home directories. */ - virtual void buttonPressed (const ButtonType buttonId, const bool isDown) = 0; + const File& operator= (const String& newFilePath) throw(); - /** Starts the device running and responding to events. + /** Copies from another file object. */ + const File& operator= (const File& otherFile) throw(); - Returns true if it managed to open the device. + /** This static constant is used for referring to an 'invalid' file. */ + static const File nonexistent; - @param inExclusiveMode if true, the remote will be grabbed exclusively for this app, - and will not be available to any other part of the system. If - false, it will be shared with other apps. - @see stop + /** Checks whether the file actually exists. + + @returns true if the file exists, either as a file or a directory. + @see existsAsFile, isDirectory */ - bool start (const bool inExclusiveMode) throw(); + bool exists() const throw(); - /** Stops the device running. - @see start + /** Checks whether the file exists and is a file rather than a directory. + + @returns true only if this is a real file, false if it's a directory + or doesn't exist + @see exists, isDirectory */ - void stop() throw(); + bool existsAsFile() const throw(); - /** Returns true if the device has been started successfully. + /** Checks whether the file is a directory that exists. + + @returns true only if the file is a directory which actually exists, so + false if it's a file or doesn't exist at all + @see exists, existsAsFile */ - bool isActive() const throw(); + bool isDirectory() const throw(); - /** Returns the ID number of the remote, if it has sent one. + /** Returns the size of the file in bytes. + + @returns the number of bytes in the file, or 0 if it doesn't exist. */ - int getRemoteId() const throw() { return remoteId; } + int64 getSize() const throw(); - juce_UseDebuggingNewOperator + /** Utility function to convert a file size in bytes to a neat string description. - /** @internal */ - void handleCallbackInternal(); + So for example 100 would return "100 bytes", 2000 would return "2 KB", + 2000000 would produce "2 MB", etc. + */ + static const String descriptionOfSizeInBytes (const int64 bytes); -private: - void* device; - void* queue; - int remoteId; + /** Returns the complete, absolute path of this file. - bool open (const bool openInExclusiveMode) throw(); + This includes the filename and all its parent folders. On Windows it'll + also include the drive letter prefix; on Mac or Linux it'll be a complete + path starting from the root folder. - AppleRemoteDevice (const AppleRemoteDevice&); - const AppleRemoteDevice& operator= (const AppleRemoteDevice&); -}; + If you just want the file's name, you should use getFileName() or + getFileNameWithoutExtension(). -#endif + @see getFileName, getRelativePathFrom + */ + const String& getFullPathName() const throw() { return fullPath; } -#endif // __JUCE_PLATFORMUTILITIES_JUCEHEADER__ -/********* End of inlined file: juce_PlatformUtilities.h *********/ + /** Returns the last section of the pathname. -#endif -#ifndef __JUCE_MEMORY_JUCEHEADER__ + Returns just the final part of the path - e.g. if the whole path + is "/moose/fish/foo.txt" this will return "foo.txt". -#endif -#ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ + For a directory, it returns the final part of the path - e.g. for the + directory "/moose/fish" it'll return "fish". -/********* Start of inlined file: juce_PerformanceCounter.h *********/ -#ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ -#define __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ + If the filename begins with a dot, it'll return the whole filename, e.g. for + "/moose/.fish", it'll return ".fish" -/** A timer for measuring performance of code and dumping the results to a file. + @see getFullPathName, getFileNameWithoutExtension + */ + const String getFileName() const throw(); - e.g. @code + /** Creates a relative path that refers to a file relatively to a given directory. - PerformanceCounter pc ("fish", 50, "/temp/myfishlog.txt"); + e.g. File ("/moose/foo.txt").getRelativePathFrom ("/moose/fish/haddock") + would return "../../foo.txt". - for (;;) - { - pc.start(); + If it's not possible to navigate from one file to the other, an absolute + path is returned. If the paths are invalid, an empty string may also be + returned. - doSomethingFishy(); + @param directoryToBeRelativeTo the directory which the resultant string will + be relative to. If this is actually a file rather than + a directory, its parent directory will be used instead. + If it doesn't exist, it's assumed to be a directory. + @see getChildFile, isAbsolutePath + */ + const String getRelativePathFrom (const File& directoryToBeRelativeTo) const throw(); - pc.stop(); - } - @endcode + /** Returns the file's extension. - In this example, the time of each period between calling start/stop will be - measured and averaged over 50 runs, and the results printed to a file - every 50 times round the loop. -*/ -class JUCE_API PerformanceCounter -{ -public: + Returns the file extension of this file, also including the dot. - /** Creates a PerformanceCounter object. + e.g. "/moose/fish/foo.txt" would return ".txt" - @param counterName the name used when printing out the statistics - @param runsPerPrintout the number of start/stop iterations before calling - printStatistics() - @param loggingFile a file to dump the results to - if this is File::nonexistent, - the results are just written to the debugger output + @see hasFileExtension, withFileExtension, getFileNameWithoutExtension */ - PerformanceCounter (const String& counterName, - int runsPerPrintout = 100, - const File& loggingFile = File::nonexistent); + const String getFileExtension() const throw(); - /** Destructor. */ - ~PerformanceCounter(); + /** Checks whether the file has a given extension. - /** Starts timing. + @param extensionToTest the extension to look for - it doesn't matter whether or + not this string has a dot at the start, so ".wav" and "wav" + will have the same effect. The comparison used is + case-insensitve. To compare with multiple extensions, this + parameter can contain multiple strings, separated by semi-colons - + so, for example: hasFileExtension (".jpeg;png;gif") would return + true if the file has any of those three extensions. - @see stop + @see getFileExtension, withFileExtension, getFileNameWithoutExtension */ - void start(); + bool hasFileExtension (const String& extensionToTest) const throw(); - /** Stops timing and prints out the results. + /** Returns a version of this file with a different file extension. - The number of iterations before doing a printout of the - results is set in the constructor. + e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html" - @see start + @param newExtension the new extension, either with or without a dot at the start (this + doesn't make any difference). To get remove a file's extension altogether, + pass an empty string into this function. + + @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension */ - void stop(); + const File withFileExtension (const String& newExtension) const throw(); - /** Dumps the current metrics to the debugger output and to a file. + /** Returns the last part of the filename, without its file extension. - As well as using Logger::outputDebugString to print the results, - this will write then to the file specified in the constructor (if - this was valid). + e.g. for "/moose/fish/foo.txt" this will return "foo". + + @see getFileName, getFileExtension, hasFileExtension, withFileExtension */ - void printStatistics(); + const String getFileNameWithoutExtension() const throw(); - juce_UseDebuggingNewOperator + /** Returns a 32-bit hash-code that identifies this file. -private: + This is based on the filename. Obviously it's possible, although unlikely, that + two files will have the same hash-code. + */ + int hashCode() const throw(); - String name; - int numRuns, runsPerPrint; - double totalTime; - int64 started; - File outputFile; -}; + /** Returns a 64-bit hash-code that identifies this file. -#endif // __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ -/********* End of inlined file: juce_PerformanceCounter.h *********/ + This is based on the filename. Obviously it's possible, although unlikely, that + two files will have the same hash-code. + */ + int64 hashCode64() const throw(); -#endif -#ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ + /** Returns a file based on a relative path. -#endif -#ifndef __JUCE_SINGLETON_JUCEHEADER__ + This will find a child file or directory of the current object. -/********* Start of inlined file: juce_Singleton.h *********/ -#ifndef __JUCE_SINGLETON_JUCEHEADER__ -#define __JUCE_SINGLETON_JUCEHEADER__ + e.g. + File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt". + File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt". -/********* Start of inlined file: juce_ScopedLock.h *********/ -#ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ -#define __JUCE_SCOPEDLOCK_JUCEHEADER__ + If the string is actually an absolute path, it will be treated as such, e.g. + File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt" -/** - Automatically locks and unlocks a CriticalSection object. + @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf + */ + const File getChildFile (String relativePath) const throw(); - Use one of these as a local variable to control access to a CriticalSection. + /** Returns a file which is in the same directory as this one. - e.g. @code + This is equivalent to getParentDirectory().getChildFile (name). - CriticalSection myCriticalSection; + @see getChildFile, getParentDirectory + */ + const File getSiblingFile (const String& siblingFileName) const throw(); - for (;;) - { - const ScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked + /** Returns the directory that contains this file or directory. - ...do some stuff... + e.g. for "/moose/fish/foo.txt" this will return "/moose/fish". + */ + const File getParentDirectory() const throw(); - // myCriticalSection gets unlocked here. - } - @endcode + /** Checks whether a file is somewhere inside a directory. - @see CriticalSection, ScopedUnlock -*/ -class JUCE_API ScopedLock -{ -public: + Returns true if this file is somewhere inside a subdirectory of the directory + that is passed in. Neither file actually has to exist, because the function + just checks the paths for similarities. - /** Creates a ScopedLock. + e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true. + File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true. + */ + bool isAChildOf (const File& potentialParentDirectory) const throw(); - As soon as it is created, this will lock the CriticalSection, and - when the ScopedLock object is deleted, the CriticalSection will - be unlocked. + /** Chooses a filename relative to this one that doesn't already exist. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline ScopedLock (const CriticalSection& lock) throw() : lock_ (lock) { lock.enter(); } + If this file is a directory, this will return a child file of this + directory that doesn't exist, by adding numbers to a prefix and suffix until + it finds one that isn't already there. - /** Destructor. + If the prefix + the suffix doesn't exist, it won't bother adding a number. - The CriticalSection will be unlocked when the destructor is called. + e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might + return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt". - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! + @param prefix the string to use for the filename before the number + @param suffix the string to add to the filename after the number + @param putNumbersInBrackets if true, this will create filenames in the + format "prefix(number)suffix", if false, it will leave the + brackets out. */ - inline ~ScopedLock() throw() { lock_.exit(); } - -private: + const File getNonexistentChildFile (const String& prefix, + const String& suffix, + bool putNumbersInBrackets = true) const throw(); - const CriticalSection& lock_; + /** Chooses a filename for a sibling file to this one that doesn't already exist. - ScopedLock (const ScopedLock&); - const ScopedLock& operator= (const ScopedLock&); -}; + If this file doesn't exist, this will just return itself, otherwise it + will return an appropriate sibling that doesn't exist, e.g. if a file + "/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt". -/** - Automatically unlocks and re-locks a CriticalSection object. + @param putNumbersInBrackets whether to add brackets around the numbers that + get appended to the new filename. + */ + const File getNonexistentSibling (const bool putNumbersInBrackets = true) const throw(); - This is the reverse of a ScopedLock object - instead of locking the critical - section for the lifetime of this object, it unlocks it. + /** Compares the pathnames for two files. */ + bool operator== (const File& otherFile) const throw(); + /** Compares the pathnames for two files. */ + bool operator!= (const File& otherFile) const throw(); - Make sure you don't try to unlock critical sections that aren't actually locked! + /** Checks whether a file can be created or written to. - e.g. @code + @returns true if it's possible to create and write to this file. If the file + doesn't already exist, this will check its parent directory to + see if writing is allowed. + @see setReadOnly + */ + bool hasWriteAccess() const throw(); - CriticalSection myCriticalSection; + /** Changes the write-permission of a file or directory. - for (;;) - { - const ScopedLock myScopedLock (myCriticalSection); - // myCriticalSection is now locked + @param shouldBeReadOnly whether to add or remove write-permission + @param applyRecursively if the file is a directory and this is true, it will + recurse through all the subfolders changing the permissions + of all files + @returns true if it manages to change the file's permissions. + @see hasWriteAccess + */ + bool setReadOnly (const bool shouldBeReadOnly, + const bool applyRecursively = false) const throw(); - ... do some stuff with it locked .. + /** Returns true if this file is a hidden or system file. - while (xyz) - { - ... do some stuff with it locked .. + The criteria for deciding whether a file is hidden are platform-dependent. + */ + bool isHidden() const throw(); - const ScopedUnlock unlocker (myCriticalSection); + /** If this file is a link, this returns the file that it points to. - // myCriticalSection is now unlocked for the remainder of this block, - // and re-locked at the end. + If this file isn't actually link, it'll just return itself. + */ + const File getLinkedTarget() const throw(); - ...do some stuff with it unlocked ... - } + /** Returns the last modification time of this file. - // myCriticalSection gets unlocked here. - } - @endcode + @returns the time, or an invalid time if the file doesn't exist. + @see setLastModificationTime, getLastAccessTime, getCreationTime + */ + const Time getLastModificationTime() const throw(); - @see CriticalSection, ScopedLock -*/ -class ScopedUnlock -{ -public: + /** Returns the last time this file was accessed. - /** Creates a ScopedUnlock. + @returns the time, or an invalid time if the file doesn't exist. + @see setLastAccessTime, getLastModificationTime, getCreationTime + */ + const Time getLastAccessTime() const throw(); - As soon as it is created, this will unlock the CriticalSection, and - when the ScopedLock object is deleted, the CriticalSection will - be re-locked. + /** Returns the time that this file was created. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. + @returns the time, or an invalid time if the file doesn't exist. + @see getLastModificationTime, getLastAccessTime */ - inline ScopedUnlock (const CriticalSection& lock) throw() : lock_ (lock) { lock.exit(); } + const Time getCreationTime() const throw(); - /** Destructor. + /** Changes the modification time for this file. - The CriticalSection will be unlocked when the destructor is called. + @param newTime the time to apply to the file + @returns true if it manages to change the file's time. + @see getLastModificationTime, setLastAccessTime, setCreationTime + */ + bool setLastModificationTime (const Time& newTime) const throw(); - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! + /** Changes the last-access time for this file. + + @param newTime the time to apply to the file + @returns true if it manages to change the file's time. + @see getLastAccessTime, setLastModificationTime, setCreationTime */ - inline ~ScopedUnlock() throw() { lock_.enter(); } + bool setLastAccessTime (const Time& newTime) const throw(); -private: + /** Changes the creation date for this file. - const CriticalSection& lock_; + @param newTime the time to apply to the file + @returns true if it manages to change the file's time. + @see getCreationTime, setLastModificationTime, setLastAccessTime + */ + bool setCreationTime (const Time& newTime) const throw(); - ScopedUnlock (const ScopedLock&); - const ScopedUnlock& operator= (const ScopedUnlock&); -}; + /** If possible, this will try to create a version string for the given file. -#endif // __JUCE_SCOPEDLOCK_JUCEHEADER__ -/********* End of inlined file: juce_ScopedLock.h *********/ + The OS may be able to look at the file and give a version for it - e.g. with + executables, bundles, dlls, etc. If no version is available, this will + return an empty string. + */ + const String getVersion() const throw(); -/** - Macro to declare member variables and methods for a singleton class. + /** Creates an empty file if it doesn't already exist. - To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion) - to the class's definition. + If the file that this object refers to doesn't exist, this will create a file + of zero size. - Then put a macro juce_ImplementSingleton (MyClass) along with the class's - implementation code. + If it already exists or is a directory, this method will do nothing. - It's also a very good idea to also add the call clearSingletonInstance() in your class's - destructor, in case it is deleted by other means than deleteInstance() + @returns true if the file has been created (or if it already existed). + @see createDirectory + */ + bool create() const throw(); - Clients can then call the static method MyClass::getInstance() to get a pointer - to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if - no instance currently exists. + /** Creates a new directory for this filename. - e.g. @code + This will try to create the file as a directory, and fill also create + any parent directories it needs in order to complete the operation. - class MySingleton - { - public: - MySingleton() - { - } + @returns true if the directory has been created successfully, (or if it + already existed beforehand). + @see create + */ + bool createDirectory() const throw(); - ~MySingleton() - { - // this ensures that no dangling pointers are left when the - // singleton is deleted. - clearSingletonInstance(); - } + /** Deletes a file. - juce_DeclareSingleton (MySingleton, false) - }; + If this file is actually a directory, it may not be deleted correctly if it + contains files. See deleteRecursively() as a better way of deleting directories. - juce_ImplementSingleton (MySingleton) + @returns true if the file has been successfully deleted (or if it didn't exist to + begin with). + @see deleteRecursively + */ + bool deleteFile() const throw(); - // example of usage: - MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one. + /** Deletes a file or directory and all its subdirectories. - ... + If this file is a directory, this will try to delete it and all its subfolders. If + it's just a file, it will just try to delete the file. - MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created). + @returns true if the file and all its subfolders have been successfully deleted + (or if it didn't exist to begin with). + @see deleteFile + */ + bool deleteRecursively() const throw(); - @endcode + /** Moves this file or folder to the trash. - If doNotRecreateAfterDeletion = true, it won't allow the object to be created more - than once during the process's lifetime - i.e. after you've created and deleted the - object, getInstance() will refuse to create another one. This can be useful to stop - objects being accidentally re-created during your app's shutdown code. + @returns true if the operation succeeded. It could fail if the trash is full, or + if the file is write-protected, so you should check the return value + and act appropriately. + */ + bool moveToTrash() const throw(); - If you know that your object will only be created and deleted by a single thread, you - can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead - of this one. + /** Moves or renames a file. - @see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded -*/ -#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \ -\ - static classname* _singletonInstance; \ - static JUCE_NAMESPACE::CriticalSection _singletonLock; \ -\ - static classname* getInstance() \ - { \ - if (_singletonInstance == 0) \ - {\ - const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ -\ - if (_singletonInstance == 0) \ - { \ - static bool alreadyInside = false; \ - static bool createdOnceAlready = false; \ -\ - const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ - jassert (! problem); \ - if (! problem) \ - { \ - createdOnceAlready = true; \ - alreadyInside = true; \ - classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ - alreadyInside = false; \ -\ - _singletonInstance = newObject; \ - } \ - } \ - } \ -\ - return _singletonInstance; \ - } \ -\ - static inline classname* getInstanceWithoutCreating() throw() \ - { \ - return _singletonInstance; \ - } \ -\ - static void deleteInstance() \ - { \ - const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ - if (_singletonInstance != 0) \ - { \ - classname* const old = _singletonInstance; \ - _singletonInstance = 0; \ - delete old; \ - } \ - } \ -\ - void clearSingletonInstance() throw() \ - { \ - if (_singletonInstance == this) \ - _singletonInstance = 0; \ - } + Tries to move a file to a different location. + If the target file already exists, this will attempt to delete it first, and + will fail if this can't be done. -/** This is a counterpart to the juce_DeclareSingleton macro. + Note that the destination file isn't the directory to put it in, it's the actual + filename that you want the new file to have. - After adding the juce_DeclareSingleton to the class definition, this macro has - to be used in the cpp file. -*/ -#define juce_ImplementSingleton(classname) \ -\ - classname* classname::_singletonInstance = 0; \ - JUCE_NAMESPACE::CriticalSection classname::_singletonLock; + @returns true if the operation succeeds + */ + bool moveFileTo (const File& targetLocation) const throw(); -/** - Macro to declare member variables and methods for a singleton class. + /** Copies a file. - This is exactly the same as juce_DeclareSingleton, but doesn't use a critical - section to make access to it thread-safe. If you know that your object will - only ever be created or deleted by a single thread, then this is a - more efficient version to use. + Tries to copy a file to a different location. + If the target file already exists, this will attempt to delete it first, and + will fail if this can't be done. - If doNotRecreateAfterDeletion = true, it won't allow the object to be created more - than once during the process's lifetime - i.e. after you've created and deleted the - object, getInstance() will refuse to create another one. This can be useful to stop - objects being accidentally re-created during your app's shutdown code. + @returns true if the operation succeeds + */ + bool copyFileTo (const File& targetLocation) const throw(); - See the documentation for juce_DeclareSingleton for more information about - how to use it, the only difference being that you have to use - juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. + /** Copies a directory. - @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal -*/ -#define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \ -\ - static classname* _singletonInstance; \ -\ - static classname* getInstance() \ - { \ - if (_singletonInstance == 0) \ - { \ - static bool alreadyInside = false; \ - static bool createdOnceAlready = false; \ -\ - const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ - jassert (! problem); \ - if (! problem) \ - { \ - createdOnceAlready = true; \ - alreadyInside = true; \ - classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ - alreadyInside = false; \ -\ - _singletonInstance = newObject; \ - } \ - } \ -\ - return _singletonInstance; \ - } \ -\ - static inline classname* getInstanceWithoutCreating() throw() \ - { \ - return _singletonInstance; \ - } \ -\ - static void deleteInstance() \ - { \ - if (_singletonInstance != 0) \ - { \ - classname* const old = _singletonInstance; \ - _singletonInstance = 0; \ - delete old; \ - } \ - } \ -\ - void clearSingletonInstance() throw() \ - { \ - if (_singletonInstance == this) \ - _singletonInstance = 0; \ - } + Tries to copy an entire directory, recursively. -/** - Macro to declare member variables and methods for a singleton class. + If this file isn't a directory or if any target files can't be created, this + will return false. - This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking - for recursion or repeated instantiation. It's intended for use as a lightweight - version of a singleton, where you're using it in very straightforward - circumstances and don't need the extra checking. + @param newDirectory the directory that this one should be copied to. Note that this + is the name of the actual directory to create, not the directory + into which the new one should be placed, so there must be enough + write privileges to create it if it doesn't exist. Any files inside + it will be overwritten by similarly named ones that are copied. + */ + bool copyDirectoryTo (const File& newDirectory) const throw(); - Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart - to this declaration, as you would with juce_DeclareSingleton_SingleThreaded. + /** Used in file searching, to specify whether to return files, directories, or both. + */ + enum TypesOfFileToFind + { + findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */ + findFiles = 2, /**< Use this flag to indicate that you want to find files. */ + findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */ + ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */ + }; - See the documentation for juce_DeclareSingleton for more information about - how to use it, the only difference being that you have to use - juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. + /** Searches inside a directory for files matching a wildcard pattern. - @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton -*/ -#define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \ -\ - static classname* _singletonInstance; \ -\ - static classname* getInstance() \ - { \ - if (_singletonInstance == 0) \ - _singletonInstance = new classname(); \ -\ - return _singletonInstance; \ - } \ -\ - static inline classname* getInstanceWithoutCreating() throw() \ - { \ - return _singletonInstance; \ - } \ -\ - static void deleteInstance() \ - { \ - if (_singletonInstance != 0) \ - { \ - classname* const old = _singletonInstance; \ - _singletonInstance = 0; \ - delete old; \ - } \ - } \ -\ - void clearSingletonInstance() throw() \ - { \ - if (_singletonInstance == this) \ - _singletonInstance = 0; \ - } + Assuming that this file is a directory, this method will search it + for either files or subdirectories whose names match a filename pattern. -/** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro. + @param results an array to which File objects will be added for the + files that the search comes up with + @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to + return files, directories, or both. If the ignoreHiddenFiles flag + is also added to this value, hidden files won't be returned + @param searchRecursively if true, all subdirectories will be recursed into to do + an exhaustive search + @param wildCardPattern the filename pattern to search for, e.g. "*.txt" + @returns the number of results that have been found - After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal - to the class definition, this macro has to be used somewhere in the cpp file. -*/ -#define juce_ImplementSingleton_SingleThreaded(classname) \ -\ - classname* classname::_singletonInstance = 0; + @see getNumberOfChildFiles, DirectoryIterator + */ + int findChildFiles (OwnedArray& results, + const int whatToLookFor, + const bool searchRecursively, + const String& wildCardPattern = JUCE_T("*")) const throw(); -#endif // __JUCE_SINGLETON_JUCEHEADER__ -/********* End of inlined file: juce_Singleton.h *********/ + /** Searches inside a directory and counts how many files match a wildcard pattern. -#endif -#ifndef __JUCE_RANDOM_JUCEHEADER__ + Assuming that this file is a directory, this method will search it + for either files or subdirectories whose names match a filename pattern, + and will return the number of matches found. -/********* Start of inlined file: juce_Random.h *********/ -#ifndef __JUCE_RANDOM_JUCEHEADER__ -#define __JUCE_RANDOM_JUCEHEADER__ + This isn't a recursive call, and will only search this directory, not + its children. -/********* Start of inlined file: juce_BitArray.h *********/ -#ifndef __JUCE_BITARRAY_JUCEHEADER__ -#define __JUCE_BITARRAY_JUCEHEADER__ + @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to + count files, directories, or both. If the ignoreHiddenFiles flag + is also added to this value, hidden files won't be counted + @param wildCardPattern the filename pattern to search for, e.g. "*.txt" + @returns the number of matches found + @see findChildFiles, DirectoryIterator + */ + int getNumberOfChildFiles (const int whatToLookFor, + const String& wildCardPattern = JUCE_T("*")) const throw(); -class MemoryBlock; + /** Returns true if this file is a directory that contains one or more subdirectories. + @see isDirectory, findChildFiles + */ + bool containsSubDirectories() const throw(); -/** - An array of on/off bits, also usable to store large binary integers. + /** Creates a stream to read from this file. - A BitArray acts like an arbitrarily large integer whose bits can be set or - cleared, and some basic mathematical operations can be done on the number as - a whole. -*/ -class JUCE_API BitArray -{ -public: + @returns a stream that will read from this file (initially positioned at the + start of the file), or 0 if the file can't be opened for some reason + @see createOutputStream, loadFileAsData + */ + FileInputStream* createInputStream() const throw(); - /** Creates an empty BitArray */ - BitArray() throw(); + /** Creates a stream to write to this file. - /** Creates a BitArray containing an integer value in its low bits. + If the file exists, the stream that is returned will be positioned ready for + writing at the end of the file, so you might want to use deleteFile() first + to write to an empty file. - The low 32 bits of the array are initialised with this value. + @returns a stream that will write to this file (initially positioned at the + end of the file), or 0 if the file can't be opened for some reason + @see createInputStream, printf, appendData, appendText */ - BitArray (const unsigned int value) throw(); - - /** Creates a BitArray containing an integer value in its low bits. + FileOutputStream* createOutputStream (const int bufferSize = 0x8000) const throw(); - The low 32 bits of the array are initialised with the absolute value - passed in, and its sign is set to reflect the sign of the number. - */ - BitArray (const int value) throw(); + /** Loads a file's contents into memory as a block of binary data. - /** Creates a BitArray containing an integer value in its low bits. + Of course, trying to load a very large file into memory will blow up, so + it's better to check first. - The low 64 bits of the array are initialised with the absolute value - passed in, and its sign is set to reflect the sign of the number. + @param result the data block to which the file's contents should be appended - note + that if the memory block might already contain some data, you + might want to clear it first + @returns true if the file could all be read into memory */ - BitArray (int64 value) throw(); - - /** Creates a copy of another BitArray. */ - BitArray (const BitArray& other) throw(); - - /** Destructor. */ - ~BitArray() throw(); + bool loadFileAsData (MemoryBlock& result) const throw(); - /** Copies another BitArray onto this one. */ - const BitArray& operator= (const BitArray& other) throw(); + /** Reads a file into memory as a string. - /** Two arrays are the same if the same bits are set. */ - bool operator== (const BitArray& other) const throw(); - /** Two arrays are the same if the same bits are set. */ - bool operator!= (const BitArray& other) const throw(); + Attempts to load the entire file as a zero-terminated string. - /** Clears all bits in the BitArray to 0. */ - void clear() throw(); + This makes use of InputStream::readEntireStreamAsString, which should + automatically cope with unicode/acsii file formats. + */ + const String loadFileAsString() const throw(); - /** Clears a particular bit in the array. */ - void clearBit (const int bitNumber) throw(); + /** Writes text to the end of the file. - /** Sets a specified bit to 1. + This will try to do a printf to the file. - If the bit number is high, this will grow the array to accomodate it. + @returns false if it can't write to the file for some reason */ - void setBit (const int bitNumber) throw(); + bool printf (const tchar* format, ...) const throw(); - /** Sets or clears a specified bit. */ - void setBit (const int bitNumber, - const bool shouldBeSet) throw(); + /** Appends a block of binary data to the end of the file. - /** Sets a range of bits to be either on or off. + This will try to write the given buffer to the end of the file. - @param startBit the first bit to change - @param numBits the number of bits to change - @param shouldBeSet whether to turn these bits on or off + @returns false if it can't write to the file for some reason */ - void setRange (int startBit, - int numBits, - const bool shouldBeSet) throw(); - - /** Inserts a bit an a given position, shifting up any bits above it. */ - void insertBit (const int bitNumber, - const bool shouldBeSet) throw(); + bool appendData (const void* const dataToAppend, + const int numberOfBytes) const throw(); - /** Returns the value of a specified bit in the array. + /** Replaces this file's contents with a given block of data. - If the index is out-of-range, the result will be false. - */ - bool operator[] (const int bit) const throw(); + This will delete the file and replace it with the given data. - /** Returns true if no bits are set. */ - bool isEmpty() const throw(); + A nice feature of this method is that it's safe - instead of deleting + the file first and then re-writing it, it creates a new temporary file, + writes the data to that, and then moves the new file to replace the existing + file. This means that if the power gets pulled out or something crashes, + you're a lot less likely to end up with an empty file.. - /** Returns a range of bits in the array as a new BitArray. + Returns true if the operation succeeds, or false if it fails. - e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits. - @see getBitRangeAsInt + @see appendText */ - const BitArray getBitRange (int startBit, int numBits) const throw(); + bool replaceWithData (const void* const dataToWrite, + const int numberOfBytes) const throw(); - /** Returns a range of bits in the array as an integer value. + /** Appends a string to the end of the file. - e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits. + This will try to append a text string to the file, as either 16-bit unicode + or 8-bit characters in the default system encoding. - Asking for more than 32 bits isn't allowed (obviously) - for that, use - getBitRange(). - */ - int getBitRangeAsInt (int startBit, int numBits) const throw(); + It can also write the 'ff fe' unicode header bytes before the text to indicate + the endianness of the file. - /** Sets a range of bits in the array based on an integer value. + Any single \\n characters in the string are replaced with \\r\\n before it is written. - Copies the given integer into the array, starting at startBit, - and only using up to numBits of the available bits. + @see replaceWithText */ - void setBitRangeAsInt (int startBit, int numBits, - unsigned int valueToSet) throw(); + bool appendText (const String& textToAppend, + const bool asUnicode = false, + const bool writeUnicodeHeaderBytes = false) const throw(); - /** Performs a bitwise OR with another BitArray. + /** Replaces this file's contents with a given text string. - The result ends up in this array. - */ - void orWith (const BitArray& other) throw(); + This will delete the file and replace it with the given text. - /** Performs a bitwise AND with another BitArray. + A nice feature of this method is that it's safe - instead of deleting + the file first and then re-writing it, it creates a new temporary file, + writes the text to that, and then moves the new file to replace the existing + file. This means that if the power gets pulled out or something crashes, + you're a lot less likely to end up with an empty file.. - The result ends up in this array. - */ - void andWith (const BitArray& other) throw(); + For an explanation of the parameters here, see the appendText() method. - /** Performs a bitwise XOR with another BitArray. + Returns true if the operation succeeds, or false if it fails. - The result ends up in this array. + @see appendText */ - void xorWith (const BitArray& other) throw(); + bool replaceWithText (const String& textToWrite, + const bool asUnicode = false, + const bool writeUnicodeHeaderBytes = false) const throw(); - /** Adds another BitArray's value to this one. + /** Creates a set of files to represent each file root. - Treating the two arrays as large positive integers, this - adds them up and puts the result in this array. + e.g. on Windows this will create files for "c:\", "d:\" etc according + to which ones are available. On the Mac/Linux, this will probably + just add a single entry for "/". */ - void add (const BitArray& other) throw(); - - /** Subtracts another BitArray's value from this one. + static void findFileSystemRoots (OwnedArray& results) throw(); - Treating the two arrays as large positive integers, this - subtracts them and puts the result in this array. + /** Finds the name of the drive on which this file lives. - Note that if the result should be negative, this won't be - handled correctly. + @returns the volume label of the drive, or an empty string if this isn't possible */ - void subtract (const BitArray& other) throw(); + const String getVolumeLabel() const throw(); - /** Multiplies another BitArray's value with this one. + /** Returns the serial number of the volume on which this file lives. - Treating the two arrays as large positive integers, this - multiplies them and puts the result in this array. + @returns the serial number, or zero if there's a problem doing this */ - void multiplyBy (const BitArray& other) throw(); - - /** Divides another BitArray's value into this one and also produces a remainder. + int getVolumeSerialNumber() const throw(); - Treating the two arrays as large positive integers, this - divides this value by the other, leaving the quotient in this - array, and the remainder is copied into the other BitArray passed in. - */ - void divideBy (const BitArray& divisor, BitArray& remainder) throw(); + /** Returns the number of bytes free on the drive that this file lives on. - /** Returns the largest value that will divide both this value and the one - passed-in. + @returns the number of bytes free, or 0 if there's a problem finding this out + @see getVolumeTotalSize */ - const BitArray findGreatestCommonDivisor (BitArray other) const throw(); + int64 getBytesFreeOnVolume() const throw(); - /** Performs a modulo operation on this value. + /** Returns the total size of the drive that contains this file. - The result is stored in this value. + @returns the total number of bytes that the volume can hold + @see getBytesFreeOnVolume */ - void modulo (const BitArray& divisor) throw(); - - /** Performs a combined exponent and modulo operation. + int64 getVolumeTotalSize() const throw(); - This BitArray's value becomes (this ^ exponent) % modulus. - */ - void exponentModulo (const BitArray& exponent, const BitArray& modulus) throw(); + /** Returns true if this file is on a CD or DVD drive. */ + bool isOnCDRomDrive() const throw(); - /** Performs an inverse modulo on the value. + /** Returns true if this file is on a hard disk. - i.e. the result is (this ^ -1) mod (modulus). + This will fail if it's a network drive, but will still be true for + removable hard-disks. */ - void inverseModulo (const BitArray& modulus) throw(); + bool isOnHardDisk() const throw(); - /** Shifts a section of bits left or right. + /** Returns true if this file is on a removable disk drive. - @param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right). - @param startBit the first bit to affect - if this is > 0, only bits above that index will be affected. + This might be a usb-drive, a CD-rom, or maybe a network drive. */ - void shiftBits (int howManyBitsLeft, - int startBit = 0) throw(); - - /** Does a signed comparison of two BitArrays. + bool isOnRemovableDrive() const throw(); - Return values are: - - 0 if the numbers are the same - - < 0 if this number is smaller than the other - - > 0 if this number is bigger than the other - */ - int compare (const BitArray& other) const throw(); + /** Launches the file as a process. - /** Compares the magnitudes of two BitArrays, ignoring their signs. + - if the file is executable, this will run it. - Return values are: - - 0 if the numbers are the same - - < 0 if this number is smaller than the other - - > 0 if this number is bigger than the other - */ - int compareAbsolute (const BitArray& other) const throw(); + - if it's a document of some kind, it will launch the document with its + default viewer application. - /** Returns true if the value is less than zero. + - if it's a folder, it will be opened in Explorer, Finder, or equivalent. - @see setNegative, negate + @see revealToUser */ - bool isNegative() const throw(); - - /** Changes the sign of the number to be positive or negative. + bool startAsProcess (const String& parameters = String::empty) const throw(); - @see isNegative, negate + /** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location. + @see startAsProcess */ - void setNegative (const bool shouldBeNegative) throw(); - - /** Inverts the sign of the number. + void revealToUser() const throw(); - @see isNegative, setNegative + /** A set of types of location that can be passed to the getSpecialLocation() method. */ - void negate() throw(); + enum SpecialLocationType + { + /** The user's home folder. This is the same as using File ("~"). */ + userHomeDirectory, - /** Counts the total number of set bits in the array. */ - int countNumberOfSetBits() const throw(); + /** The user's default documents folder. On Windows, this might be the user's + "My Documents" folder. On the Mac it'll be their "Documents" folder. Linux + doesn't tend to have one of these, so it might just return their home folder. + */ + userDocumentsDirectory, - /** Looks for the index of the next set bit after a given starting point. + /** The folder that contains the user's desktop objects. */ + userDesktopDirectory, - searches from startIndex (inclusive) upwards for the first set bit, - and returns its index. + /** The folder in which applications store their persistent user-specific settings. + On Windows, this might be "\Documents and Settings\username\Application Data". + On the Mac, it might be "~/Library". If you're going to store your settings in here, + always create your own sub-folder to put them in, to avoid making a mess. + */ + userApplicationDataDirectory, - If no set bits are found, it returns -1. - */ - int findNextSetBit (int startIndex = 0) const throw(); + /** An equivalent of the userApplicationDataDirectory folder that is shared by all users + of the computer, rather than just the current user. - /** Looks for the index of the next clear bit after a given starting point. + On the Mac it'll be "/Library", on Windows, it could be something like + "\Documents and Settings\All Users\Application Data". - searches from startIndex (inclusive) upwards for the first clear bit, - and returns its index. - */ - int findNextClearBit (int startIndex = 0) const throw(); + Depending on the setup, this folder may be read-only. + */ + commonApplicationDataDirectory, - /** Returns the index of the highest set bit in the array. + /** The folder that should be used for temporary files. - If the array is empty, this will return -1. - */ - int getHighestBit() const throw(); + Always delete them when you're finished, to keep the user's computer tidy! + */ + tempDirectory, - /** Converts the array to a number string. + /** Returns this application's executable file. - Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). + If running as a plug-in or DLL, this will (where possible) be the DLL rather than the + host app. - If minuimumNumCharacters is greater than 0, the returned string will be - padded with leading zeros to reach at least that length. - */ - const String toString (const int base, const int minimumNumCharacters = 1) const throw(); + On the mac this will return the unix binary, not the package folder - see + currentApplicationFile for that. - /** Converts a number string to an array. + See also invokedExecutableFile, which is similar, but if the exe was launched from a + file link, invokedExecutableFile will return the name of the link. + */ + currentExecutableFile, - Any non-valid characters will be ignored. + /** Returns this application's location. - Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). - */ - void parseString (const String& text, - const int base) throw(); + If running as a plug-in or DLL, this will (where possible) be the DLL rather than the + host app. - /** Turns the array into a block of binary data. + On the mac this will return the package folder (if it's in one), not the unix binary + that's inside it - compare with currentExecutableFile. + */ + currentApplicationFile, - The data is arranged as little-endian, so the first byte of data is the low 8 bits - of the array, and so on. + /** Returns the file that was invoked to launch this executable. + This may differ from currentExecutableFile if the app was started from e.g. a link - this + will return the name of the link that was used, whereas currentExecutableFile will return + the actual location of the target executable. + */ + invokedExecutableFile, - @see loadFromMemoryBlock - */ - const MemoryBlock toMemoryBlock() const throw(); + /** The directory in which applications normally get installed. - /** Copies a block of raw data onto this array. + So on windows, this would be something like "c:\program files", on the + Mac "/Applications", or "/usr" on linux. + */ + globalApplicationsDirectory, - The data is arranged as little-endian, so the first byte of data is the low 8 bits - of the array, and so on. + /** The most likely place where a user might store their music files. + */ + userMusicDirectory, - @see toMemoryBlock - */ - void loadFromMemoryBlock (const MemoryBlock& data) throw(); + /** The most likely place where a user might store their movie files. + */ + userMoviesDirectory, + }; - juce_UseDebuggingNewOperator + /** Finds the location of a special type of file or directory, such as a home folder or + documents folder. -private: - void ensureSize (const int numVals) throw(); - unsigned int* values; - int numValues, highestBit; - bool negative; -}; + @see SpecialLocationType + */ + static const File JUCE_CALLTYPE getSpecialLocation (const SpecialLocationType type); -#endif // __JUCE_BITARRAY_JUCEHEADER__ -/********* End of inlined file: juce_BitArray.h *********/ + /** Returns a temporary file in the system's temp directory. -/** - A simple pseudo-random number generator. -*/ -class JUCE_API Random -{ -public: + This will try to return the name of a non-existent temp file. - /** Creates a Random object based on a seed value. + To get the temp folder, you can use getSpecialLocation (File::tempDirectory). + */ + static const File createTempFile (const String& fileNameEnding) throw(); - For a given seed value, the subsequent numbers generated by this object - will be predictable, so a good idea is to set this value based - on the time, e.g. + /** Returns the current working directory. - new Random (Time::currentTimeMillis()) + @see setAsCurrentWorkingDirectory */ - Random (const int64 seedValue) throw(); + static const File getCurrentWorkingDirectory() throw(); - /** Destructor. */ - ~Random() throw(); + /** Sets the current working directory to be this file. - /** Returns the next random 32 bit integer. + For this to work the file must point to a valid directory. - @returns a random integer from the full range 0x80000000 to 0x7fffffff + @returns true if the current directory has been changed. + @see getCurrentWorkingDirectory */ - int nextInt() throw(); + bool setAsCurrentWorkingDirectory() const throw(); - /** Returns the next random number, limited to a given range. + /** The system-specific file separator character. - @returns a random integer between 0 (inclusive) and maxValue (exclusive). + On Windows, this will be '\', on Mac/Linux, it'll be '/' */ - int nextInt (const int maxValue) throw(); + static const tchar separator; - /** Returns the next 64-bit random number. + /** The system-specific file separator character, as a string. - @returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff + On Windows, this will be '\', on Mac/Linux, it'll be '/' */ - int64 nextInt64() throw(); + static const tchar* separatorString; - /** Returns the next random floating-point number. + /** Removes illegal characters from a filename. - @returns a random value in the range 0 to 1.0 - */ - float nextFloat() throw(); + This will return a copy of the given string after removing characters + that are not allowed in a legal filename, and possibly shortening the + string if it's too long. - /** Returns the next random floating-point number. + Because this will remove slashes, don't use it on an absolute pathname. - @returns a random value in the range 0 to 1.0 + @see createLegalPathName */ - double nextDouble() throw(); + static const String createLegalFileName (const String& fileNameToFix) throw(); - /** Returns the next random boolean value. - */ - bool nextBool() throw(); + /** Removes illegal characters from a pathname. - /** Returns a BitArray containing a random number. + Similar to createLegalFileName(), but this won't remove slashes, so can + be used on a complete pathname. - @returns a random value in the range 0 to (maximumValue - 1). + @see createLegalFileName */ - const BitArray nextLargeNumber (const BitArray& maximumValue) throw(); - - /** Sets a range of bits in a BitArray to random values. */ - void fillBitsRandomly (BitArray& arrayToChange, int startBit, int numBits) throw(); - - /** To avoid the overhead of having to create a new Random object whenever - you need a number, this is a shared application-wide object that - can be used. + static const String createLegalPathName (const String& pathNameToFix) throw(); - It's not thread-safe though, so threads should use their own Random object. + /** Indicates whether filenames are case-sensitive on the current operating system. */ - static Random& getSystemRandom() throw(); - - /** Resets this Random object to a given seed value. */ - void setSeed (const int64 newSeed) throw(); - - /** Reseeds this generator using a value generated from various semi-random system - properties like the current time, etc. + static bool areFileNamesCaseSensitive(); - Because this function convolves the time with the last seed value, calling - it repeatedly will increase the randomness of the final result. + /** Returns true if the string seems to be a fully-specified absolute path. */ - void setSeedRandomly(); + static bool isAbsolutePath (const String& path) throw(); juce_UseDebuggingNewOperator private: - int64 seed; -}; - -#endif // __JUCE_RANDOM_JUCEHEADER__ -/********* End of inlined file: juce_Random.h *********/ -#endif -#ifndef __JUCE_RELATIVETIME_JUCEHEADER__ - -#endif -#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ + String fullPath; -/********* Start of inlined file: juce_SystemStats.h *********/ -#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ -#define __JUCE_SYSTEMSTATS_JUCEHEADER__ + // internal way of contructing a file without checking the path + friend class DirectoryIterator; + File (const String&, int) throw(); + const String getPathUpToLastSlash() const throw(); +}; -/** - Contains methods for finding out about the current hardware and OS configuration. -*/ -class JUCE_API SystemStats -{ -public: +#endif // __JUCE_FILE_JUCEHEADER__ +/********* End of inlined file: juce_File.h *********/ - /** Returns the current version of JUCE, +/** A handy macro to make it easy to iterate all the child elements in an XmlElement. - (just in case you didn't already know at compile-time.) + The parentXmlElement should be a reference to the parent XML, and the childElementVariableName + will be the name of a pointer to each child element. - See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros. - */ - static const String getJUCEVersion() throw(); + E.g. @code + XmlElement* myParentXml = createSomeKindOfXmlDocument(); - /** The set of possible results of the getOperatingSystemType() method. - */ - enum OperatingSystemType + forEachXmlChildElement (*myParentXml, child) { - UnknownOS = 0, + if (child->hasTagName ("FOO")) + doSomethingWithXmlElement (child); + } - MacOSX = 0x1000, - Linux = 0x2000, + @endcode - Win95 = 0x4001, - Win98 = 0x4002, - WinNT351 = 0x4103, - WinNT40 = 0x4104, - Win2000 = 0x4105, - WinXP = 0x4106, - WinVista = 0x4107, - Windows7 = 0x4108, + @see forEachXmlChildElementWithTagName +*/ +#define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ +\ + for (XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \ + childElementVariableName != 0; \ + childElementVariableName = childElementVariableName->getNextElement()) - Windows = 0x4000, /**< To test whether any version of Windows is running, - you can use the expression ((getOperatingSystemType() & Windows) != 0). */ - WindowsNT = 0x0100, /**< To test whether the platform is Windows NT or later (i.e. not Win95 or 98), - you can use the expression ((getOperatingSystemType() & WindowsNT) != 0). */ - }; +/** A macro that makes it easy to iterate all the child elements of an XmlElement + which have a specified tag. - /** Returns the type of operating system we're running on. + This does the same job as the forEachXmlChildElement macro, but only for those + elements that have a particular tag name. - @returns one of the values from the OperatingSystemType enum. - @see getOperatingSystemName - */ - static OperatingSystemType getOperatingSystemType() throw(); + The parentXmlElement should be a reference to the parent XML, and the childElementVariableName + will be the name of a pointer to each child element. The requiredTagName is the + tag name to match. - /** Returns the name of the type of operating system we're running on. + E.g. @code + XmlElement* myParentXml = createSomeKindOfXmlDocument(); - @returns a string describing the OS type. - @see getOperatingSystemType - */ - static const String getOperatingSystemName() throw(); + forEachXmlChildElementWithTagName (*myParentXml, child, T("MYTAG")) + { + // the child object is now guaranteed to be a element.. + doSomethingWithMYTAGElement (child); + } - /** Returns true if the OS is 64-bit, or false for a 32-bit OS. - */ - static bool isOperatingSystem64Bit() throw(); + @endcode - // CPU and memory information.. + @see forEachXmlChildElement +*/ +#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ +\ + for (XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \ + childElementVariableName != 0; \ + childElementVariableName = childElementVariableName->getNextElementWithTagName (requiredTagName)) - /** Returns the approximate CPU speed. +/** Used to build a tree of elements representing an XML document. - @returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on - what year you're reading this...) - */ - static int getCpuSpeedInMegaherz() throw(); + An XML document can be parsed into a tree of XmlElements, each of which + represents an XML tag structure, and which may itself contain other + nested elements. - /** Returns a string to indicate the CPU vendor. + An XmlElement can also be converted back into a text document, and has + lots of useful methods for manipulating its attributes and sub-elements, + so XmlElements can actually be used as a handy general-purpose data + structure. - Might not be known on some systems. - */ - static const String getCpuVendor() throw(); + Here's an example of parsing some elements: @code + // check we're looking at the right kind of document.. + if (myElement->hasTagName ("ANIMALS")) + { + // now we'll iterate its sub-elements looking for 'giraffe' elements.. + forEachXmlChildElement (*myElement, e) + { + if (e->hasTagName ("GIRAFFE")) + { + // found a giraffe, so use some of its attributes.. - /** Checks whether Intel MMX instructions are available. */ - static bool hasMMX() throw(); + String giraffeName = e->getStringAttribute ("name"); + int giraffeAge = e->getIntAttribute ("age"); + bool isFriendly = e->getBoolAttribute ("friendly"); + } + } + } + @endcode - /** Checks whether Intel SSE instructions are available. */ - static bool hasSSE() throw(); + And here's an example of how to create an XML document from scratch: @code + // create an outer node called "ANIMALS" + XmlElement animalsList ("ANIMALS"); - /** Checks whether Intel SSE2 instructions are available. */ - static bool hasSSE2() throw(); + for (int i = 0; i < numAnimals; ++i) + { + // create an inner element.. + XmlElement* giraffe = new XmlElement ("GIRAFFE"); - /** Checks whether AMD 3DNOW instructions are available. */ - static bool has3DNow() throw(); + giraffe->setAttribute ("name", "nigel"); + giraffe->setAttribute ("age", 10); + giraffe->setAttribute ("friendly", true); - /** Returns the number of CPUs. - */ - static int getNumCpus() throw(); + // ..and add our new element to the parent node + animalsList.addChildElement (giraffe); + } - /** Returns a clock-cycle tick counter, if available. + // now we can turn the whole thing into a text document.. + String myXmlDoc = animalsList.createDocument (String::empty); + @endcode - If the machine can do it, this will return a tick-count - where each tick is one cpu clock cycle - used for profiling - code. + @see XmlDocument +*/ +class JUCE_API XmlElement +{ +public: - @returns the tick count, or zero if not available. - */ - static int64 getClockCycleCounter() throw(); + /** Creates an XmlElement with this tag name. */ + XmlElement (const String& tagName) throw(); - /** Finds out how much RAM is in the machine. + /** Creates a (deep) copy of another element. */ + XmlElement (const XmlElement& other) throw(); - @returns the approximate number of megabytes of memory, or zero if - something goes wrong when finding out. - */ - static int getMemorySizeInMegabytes() throw(); + /** Creates a (deep) copy of another element. */ + const XmlElement& operator= (const XmlElement& other) throw(); - /** Returns the system page-size. + /** Deleting an XmlElement will also delete all its child elements. */ + ~XmlElement() throw(); - This is only used by programmers with beards. - */ - static int getPageSize() throw(); + /** Compares two XmlElements to see if they contain the same text and attiributes. - /** Returns a list of MAC addresses found on this machine. + The elements are only considered equivalent if they contain the same attiributes + with the same values, and have the same sub-nodes. - @param addresses an array into which the MAC addresses should be copied - @param maxNum the number of elements in this array - @param littleEndian the endianness of the numbers to return. If this is true, - the least-significant byte of each number is the first byte - of the mac address. If false, the least significant byte is - the last number. Note that the default values of this parameter - are different on Mac/PC to avoid breaking old software that was - written before this parameter was added (when the two systems - defaulted to using different endiannesses). In newer - software you probably want to specify an explicit value - for this. - @returns the number of MAC addresses that were found + @param other the other element to compare to + @param ignoreOrderOfAttributes if true, this means that two elements with the + same attributes in a different order will be + considered the same; if false, the attributes must + be in the same order as well */ - static int getMACAddresses (int64* addresses, int maxNum, -#if JUCE_MAC - const bool littleEndian = true) throw(); -#else - const bool littleEndian = false) throw(); -#endif + bool isEquivalentTo (const XmlElement* const other, + const bool ignoreOrderOfAttributes) const throw(); - // not-for-public-use platform-specific method gets called at startup to initialise things. - static void initialiseStats() throw(); -}; + /** Returns an XML text document that represents this element. -#endif // __JUCE_SYSTEMSTATS_JUCEHEADER__ -/********* End of inlined file: juce_SystemStats.h *********/ + The string returned can be parsed to recreate the same XmlElement that + was used to create it. -#endif -#ifndef __JUCE_TIME_JUCEHEADER__ + @param dtdToUse the DTD to add to the document + @param allOnOneLine if true, this means that the document will not contain any + linefeeds, so it'll be smaller but not very easy to read. + @param includeXmlHeader whether to add the ", this would return + "MOOSE". - /** Creates a copy of another UUID. */ - Uuid (const Uuid& other); + @see hasTagName + */ + inline const String& getTagName() const throw() { return tagName; } - /** Copies another UUID. */ - Uuid& operator= (const Uuid& other); + /** Tests whether this element has a particular tag name. - /** Returns true if the ID is zero. */ - bool isNull() const throw(); + @param possibleTagName the tag name you're comparing it with - /** Compares two UUIDs. */ - bool operator== (const Uuid& other) const; + @see getTagName + */ + bool hasTagName (const tchar* const possibleTagName) const throw(); - /** Compares two UUIDs. */ - bool operator!= (const Uuid& other) const; + /** Returns the number of XML attributes this element contains. - /** Returns a stringified version of this UUID. + E.g. for an element such as \, this would + return 2. + */ + int getNumAttributes() const throw(); - A Uuid object can later be reconstructed from this string using operator= or - the constructor that takes a string parameter. + /** Returns the name of one of the elements attributes. - @returns a 32 character hex string. + E.g. for an element such as \, then + getAttributeName(1) would return "antlers". + + @see getAttributeValue, getStringAttribute */ - const String toString() const; + const String& getAttributeName (const int attributeIndex) const throw(); - /** Creates an ID from an encoded string version. + /** Returns the value of one of the elements attributes. - @see toString + E.g. for an element such as \, then + getAttributeName(1) would return "2". + + @see getAttributeName, getStringAttribute */ - Uuid (const String& uuidString); + const String& getAttributeValue (const int attributeIndex) const throw(); - /** Copies from a stringified UUID. + // Attribute-handling methods.. - The string passed in should be one that was created with the toString() method. + /** Checks whether the element contains an attribute with a certain name. */ + bool hasAttribute (const tchar* const attributeName) const throw(); + + /** Returns the value of a named attribute. + + @param attributeName the name of the attribute to look up + @param defaultReturnValue a value to return if the element doesn't have an attribute + with this name */ - Uuid& operator= (const String& uuidString); + const String getStringAttribute (const tchar* const attributeName, + const tchar* const defaultReturnValue = 0) const throw(); - /** Returns a pointer to the internal binary representation of the ID. + /** Compares the value of a named attribute with a value passed-in. - This is an array of 16 bytes. To reconstruct a Uuid from its data, use - the constructor or operator= method that takes an array of uint8s. + @param attributeName the name of the attribute to look up + @param stringToCompareAgainst the value to compare it with + @param ignoreCase whether the comparison should be case-insensitive + @returns true if the value of the attribute is the same as the string passed-in; + false if it's different (or if no such attribute exists) */ - const uint8* getRawData() const throw() { return value.asBytes; } + bool compareAttribute (const tchar* const attributeName, + const tchar* const stringToCompareAgainst, + const bool ignoreCase = false) const throw(); - /** Creates a UUID from a 16-byte array. + /** Returns the value of a named attribute as an integer. - @see getRawData + This will try to find the attribute and convert it to an integer (using + the String::getIntValue() method). + + @param attributeName the name of the attribute to look up + @param defaultReturnValue a value to return if the element doesn't have an attribute + with this name + @see setAttribute (const tchar* const, int) */ - Uuid (const uint8* const rawData); + int getIntAttribute (const tchar* const attributeName, + const int defaultReturnValue = 0) const throw(); - /** Sets this UUID from 16-bytes of raw data. */ - Uuid& operator= (const uint8* const rawData); + /** Returns the value of a named attribute as floating-point. - juce_UseDebuggingNewOperator + This will try to find the attribute and convert it to an integer (using + the String::getDoubleValue() method). -private: - union - { - uint8 asBytes [16]; - int asInt[4]; - int64 asInt64[2]; + @param attributeName the name of the attribute to look up + @param defaultReturnValue a value to return if the element doesn't have an attribute + with this name + @see setAttribute (const tchar* const, double) + */ + double getDoubleAttribute (const tchar* const attributeName, + const double defaultReturnValue = 0.0) const throw(); - } value; -}; + /** Returns the value of a named attribute as a boolean. -#endif // __JUCE_UUID_JUCEHEADER__ -/********* End of inlined file: juce_Uuid.h *********/ + This will try to find the attribute and interpret it as a boolean. To do this, + it'll return true if the value is "1", "true", "y", etc, or false for other + values. -#endif -#ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ + @param attributeName the name of the attribute to look up + @param defaultReturnValue a value to return if the element doesn't have an attribute + with this name + */ + bool getBoolAttribute (const tchar* const attributeName, + const bool defaultReturnValue = false) const throw(); -#endif -#ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ + /** Adds a named attribute to the element. -#endif -#ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ + If the element already contains an attribute with this name, it's value will + be updated to the new value. If there's no such attribute yet, a new one will + be added. -#endif -#ifndef __JUCE_ARRAY_JUCEHEADER__ + Note that there are other setAttribute() methods that take integers, + doubles, etc. to make it easy to store numbers. -#endif -#ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ + @param attributeName the name of the attribute to set + @param newValue the value to set it to + @see removeAttribute + */ + void setAttribute (const tchar* const attributeName, + const String& newValue) throw(); -#endif -#ifndef __JUCE_VARIANT_JUCEHEADER__ + /** Adds a named attribute to the element. -/********* Start of inlined file: juce_Variant.h *********/ -#ifndef __JUCE_VARIANT_JUCEHEADER__ -#define __JUCE_VARIANT_JUCEHEADER__ + If the element already contains an attribute with this name, it's value will + be updated to the new value. If there's no such attribute yet, a new one will + be added. -/********* Start of inlined file: juce_ReferenceCountedObject.h *********/ -#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ -#define __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ + Note that there are other setAttribute() methods that take integers, + doubles, etc. to make it easy to store numbers. -/** - Adds reference-counting to an object. + @param attributeName the name of the attribute to set + @param newValue the value to set it to + */ + void setAttribute (const tchar* const attributeName, + const tchar* const newValue) throw(); - To add reference-counting to a class, derive it from this class, and - use the ReferenceCountedObjectPtr class to point to it. + /** Adds a named attribute to the element, setting it to an integer value. - e.g. @code - class MyClass : public ReferenceCountedObject - { - void foo(); + If the element already contains an attribute with this name, it's value will + be updated to the new value. If there's no such attribute yet, a new one will + be added. - // This is a neat way of declaring a typedef for a pointer class, - // rather than typing out the full templated name each time.. - typedef ReferenceCountedObjectPtr Ptr; - }; + Note that there are other setAttribute() methods that take integers, + doubles, etc. to make it easy to store numbers. - MyClass::Ptr p = new MyClass(); - MyClass::Ptr p2 = p; - p = 0; - p2->foo(); - @endcode + @param attributeName the name of the attribute to set + @param newValue the value to set it to + */ + void setAttribute (const tchar* const attributeName, + const int newValue) throw(); - Once a new ReferenceCountedObject has been assigned to a pointer, be - careful not to delete the object manually. + /** Adds a named attribute to the element, setting it to a floating-point value. - @see ReferenceCountedObjectPtr, ReferenceCountedArray -*/ -class JUCE_API ReferenceCountedObject -{ -public: + If the element already contains an attribute with this name, it's value will + be updated to the new value. If there's no such attribute yet, a new one will + be added. - /** Increments the object's reference count. + Note that there are other setAttribute() methods that take integers, + doubles, etc. to make it easy to store numbers. - This is done automatically by the smart pointer, but is public just - in case it's needed for nefarious purposes. + @param attributeName the name of the attribute to set + @param newValue the value to set it to */ - inline void incReferenceCount() throw() - { - atomicIncrement (refCounts); + void setAttribute (const tchar* const attributeName, + const double newValue) throw(); - jassert (refCounts > 0); - } + /** Removes a named attribute from the element. - /** Decreases the object's reference count. + @param attributeName the name of the attribute to remove + @see removeAllAttributes + */ + void removeAttribute (const tchar* const attributeName) throw(); - If the count gets to zero, the object will be deleted. + /** Removes all attributes from this element. */ - inline void decReferenceCount() throw() - { - jassert (refCounts > 0); + void removeAllAttributes() throw(); - if (atomicDecrementAndReturn (refCounts) == 0) - delete this; - } + // Child element methods.. - /** Returns the object's current reference count. */ - inline int getReferenceCount() const throw() - { - return refCounts; - } + /** Returns the first of this element's sub-elements. -protected: + see getNextElement() for an example of how to iterate the sub-elements. - /** Creates the reference-counted object (with an initial ref count of zero). */ - ReferenceCountedObject() - : refCounts (0) - { - } + @see forEachXmlChildElement + */ + XmlElement* getFirstChildElement() const throw() { return firstChildElement; } - /** Destructor. */ - virtual ~ReferenceCountedObject() - { - // it's dangerous to delete an object that's still referenced by something else! - jassert (refCounts == 0); - } + /** Returns the next of this element's siblings. -private: + This can be used for iterating an element's sub-elements, e.g. + @code + XmlElement* child = myXmlDocument->getFirstChildElement(); - int refCounts; -}; + while (child != 0) + { + ...do stuff with this child.. -/** - Used to point to an object of type ReferenceCountedObject. + child = child->getNextElement(); + } + @endcode - It's wise to use a typedef instead of typing out the templated name - each time - e.g. + Note that when iterating the child elements, some of them might be + text elements as well as XML tags - use isTextElement() to work this + out. - typedef ReferenceCountedObjectPtr MyClassPtr; + Also, it's much easier and neater to use this method indirectly via the + forEachXmlChildElement macro. - @see ReferenceCountedObject, ReferenceCountedObjectArray -*/ -template -class ReferenceCountedObjectPtr -{ -public: + @returns the sibling element that follows this one, or zero if this is the last + element in its parent - /** Creates a pointer to a null object. */ - inline ReferenceCountedObjectPtr() throw() - : referencedObject (0) - { - } + @see getNextElement, isTextElement, forEachXmlChildElement + */ + inline XmlElement* getNextElement() const throw() { return nextElement; } - /** Creates a pointer to an object. + /** Returns the next of this element's siblings which has the specified tag + name. - This will increment the object's reference-count if it is non-null. + This is like getNextElement(), but will scan through the list until it + finds an element with the given tag name. + + @see getNextElement, forEachXmlChildElementWithTagName */ - inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) throw() - : referencedObject (refCountedObject) - { - if (refCountedObject != 0) - refCountedObject->incReferenceCount(); - } + XmlElement* getNextElementWithTagName (const tchar* const requiredTagName) const; - /** Copies another pointer. + /** Returns the number of sub-elements in this element. - This will increment the object's reference-count (if it is non-null). + @see getChildElement */ - inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) throw() - : referencedObject (other.referencedObject) - { - if (referencedObject != 0) - referencedObject->incReferenceCount(); - } + int getNumChildElements() const throw(); - /** Changes this pointer to point at a different object. + /** Returns the sub-element at a certain index. - The reference count of the old object is decremented, and it might be - deleted if it hits zero. The new object's count is incremented. - */ - const ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) - { - ReferenceCountedObjectClass* const newObject = other.referencedObject; + It's not very efficient to iterate the sub-elements by index - see + getNextElement() for an example of how best to iterate. - if (newObject != referencedObject) - { - if (newObject != 0) - newObject->incReferenceCount(); + @returns the n'th child of this element, or 0 if the index is out-of-range + @see getNextElement, isTextElement, getChildByName + */ + XmlElement* getChildElement (const int index) const throw(); - ReferenceCountedObjectClass* const oldObject = referencedObject; - referencedObject = newObject; + /** Returns the first sub-element with a given tag-name. - if (oldObject != 0) - oldObject->decReferenceCount(); - } + @param tagNameToLookFor the tag name of the element you want to find + @returns the first element with this tag name, or 0 if none is found + @see getNextElement, isTextElement, getChildElement + */ + XmlElement* getChildByName (const tchar* const tagNameToLookFor) const throw(); - return *this; - } + /** Appends an element to this element's list of children. - /** Changes this pointer to point at a different object. + Child elements are deleted automatically when their parent is deleted, so + make sure the object that you pass in will not be deleted by anything else, + and make sure it's not already the child of another element. - The reference count of the old object is decremented, and it might be - deleted if it hits zero. The new object's count is incremented. + @see getFirstChildElement, getNextElement, getNumChildElements, + getChildElement, removeChildElement */ - const ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject) - { - if (referencedObject != newObject) - { - if (newObject != 0) - newObject->incReferenceCount(); + void addChildElement (XmlElement* const newChildElement) throw(); - ReferenceCountedObjectClass* const oldObject = referencedObject; - referencedObject = newObject; + /** Inserts an element into this element's list of children. - if (oldObject != 0) - oldObject->decReferenceCount(); - } + Child elements are deleted automatically when their parent is deleted, so + make sure the object that you pass in will not be deleted by anything else, + and make sure it's not already the child of another element. - return *this; - } + @param newChildNode the element to add + @param indexToInsertAt the index at which to insert the new element - if this is + below zero, it will be added to the end of the list + @see addChildElement, insertChildElement + */ + void insertChildElement (XmlElement* const newChildNode, + int indexToInsertAt) throw(); - /** Destructor. + /** Replaces one of this element's children with another node. - This will decrement the object's reference-count, and may delete it if it - gets to zero. + If the current element passed-in isn't actually a child of this element, + this will return false and the new one won't be added. Otherwise, the + existing element will be deleted, replaced with the new one, and it + will return true. */ - inline ~ReferenceCountedObjectPtr() - { - if (referencedObject != 0) - referencedObject->decReferenceCount(); - } + bool replaceChildElement (XmlElement* const currentChildElement, + XmlElement* const newChildNode) throw(); - /** Returns the object that this pointer references. + /** Removes a child element. - The pointer returned may be zero, of course. + @param childToRemove the child to look for and remove + @param shouldDeleteTheChild if true, the child will be deleted, if false it'll + just remove it */ - inline operator ReferenceCountedObjectClass*() const throw() - { - return referencedObject; - } + void removeChildElement (XmlElement* const childToRemove, + const bool shouldDeleteTheChild) throw(); - /** Returns true if this pointer refers to the given object. */ - inline bool operator== (ReferenceCountedObjectClass* const object) const throw() - { - return referencedObject == object; - } + /** Deletes all the child elements in the element. - /** Returns true if this pointer doesn't refer to the given object. */ - inline bool operator!= (ReferenceCountedObjectClass* const object) const throw() - { - return referencedObject != object; - } + @see removeChildElement, deleteAllChildElementsWithTagName + */ + void deleteAllChildElements() throw(); - // the -> operator is called on the referenced object - inline ReferenceCountedObjectClass* operator->() const throw() - { - return referencedObject; - } + /** Deletes all the child elements with a given tag name. -private: + @see removeChildElement + */ + void deleteAllChildElementsWithTagName (const tchar* const tagName) throw(); - ReferenceCountedObjectClass* referencedObject; -}; + /** Returns true if the given element is a child of this one. */ + bool containsChildElement (const XmlElement* const possibleChild) const throw(); -#endif // __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ -/********* End of inlined file: juce_ReferenceCountedObject.h *********/ + /** Recursively searches all sub-elements to find one that contains the specified + child element. + */ + XmlElement* findParentElementOf (const XmlElement* const elementToLookFor) throw(); -/********* Start of inlined file: juce_OutputStream.h *********/ -#ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ -#define __JUCE_OUTPUTSTREAM_JUCEHEADER__ + /** Sorts the child elements using a comparator. -/********* Start of inlined file: juce_InputStream.h *********/ -#ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ -#define __JUCE_INPUTSTREAM_JUCEHEADER__ + This will use a comparator object to sort the elements into order. The object + passed must have a method of the form: + @code + int compareElements (const XmlElement* first, const XmlElement* second); + @endcode -/** The base class for streams that read data. + ..and this method must return: + - a value of < 0 if the first comes before the second + - a value of 0 if the two objects are equivalent + - a value of > 0 if the second comes before the first - Input and output streams are used throughout the library - subclasses can override - some or all of the virtual functions to implement their behaviour. + To improve performance, the compareElements() method can be declared as static or const. - @see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream -*/ -class JUCE_API InputStream -{ -public: - /** Destructor. */ - virtual ~InputStream() {} + @param comparator the comparator to use for comparing elements. + @param retainOrderOfEquivalentItems if this is true, then items + which the comparator says are equivalent will be + kept in the order in which they currently appear + in the array. This is slower to perform, but may + be important in some cases. If it's false, a faster + algorithm is used, but equivalent elements may be + rearranged. + */ + template + void sortChildElements (ElementComparator& comparator, + const bool retainOrderOfEquivalentItems = false) throw() + { + const int num = getNumChildElements(); - /** Returns the total number of bytes available for reading in this stream. + if (num > 1) + { + HeapBlock elems (num); + getChildElementsAsArray (elems); + sortArray (comparator, (XmlElement**) elems, 0, num - 1, retainOrderOfEquivalentItems); + reorderChildElements (elems, num); + } + } - Note that this is the number of bytes available from the start of the - stream, not from the current position. + /** Returns true if this element is a section of text. - If the size of the stream isn't actually known, this may return -1. + Elements can either be an XML tag element or a secton of text, so this + is used to find out what kind of element this one is. + + @see getAllText, addTextElement, deleteAllTextElements */ - virtual int64 getTotalLength() = 0; + bool isTextElement() const throw(); - /** Returns true if the stream has no more data to read. */ - virtual bool isExhausted() = 0; + /** Returns the text for a text element. - /** Reads a set of bytes from the stream into a memory buffer. + Note that if you have an element like this: - This is the only read method that subclasses actually need to implement, as the - InputStream base class implements the other read methods in terms of this one (although - it's often more efficient for subclasses to implement them directly). + @codehello@endcode - @param destBuffer the destination buffer for the data - @param maxBytesToRead the maximum number of bytes to read - make sure the - memory block passed in is big enough to contain this - many bytes. + then calling getText on the "xyz" element won't return "hello", because that is + actually stored in a special text sub-element inside the xyz element. To get the + "hello" string, you could either call getText on the (unnamed) sub-element, or + use getAllSubText() to do this automatically. - @returns the actual number of bytes that were read, which may be less than - maxBytesToRead if the stream is exhausted before it gets that far + @see isTextElement, getAllSubText, getChildElementAllSubText */ - virtual int read (void* destBuffer, - int maxBytesToRead) = 0; - - /** Reads a byte from the stream. + const String getText() const throw(); - If the stream is exhausted, this will return zero. + /** Sets the text in a text element. - @see OutputStream::writeByte + Note that this is only a valid call if this element is a text element. If it's + not, then no action will be performed. */ - virtual char readByte(); + void setText (const String& newText) throw(); - /** Reads a boolean from the stream. + /** Returns all the text from this element's child nodes. - The bool is encoded as a single byte - 1 for true, 0 for false. + This iterates all the child elements and when it finds text elements, + it concatenates their text into a big string which it returns. - If the stream is exhausted, this will return false. + E.g. @code hello there @endcode + if you called getAllSubText on the "xyz" element, it'd return "hello there". - @see OutputStream::writeBool + @see isTextElement, getChildElementAllSubText, getText, addTextElement */ - virtual bool readBool(); - - /** Reads two bytes from the stream as a little-endian 16-bit value. + const String getAllSubText() const throw(); - If the next two bytes read are byte1 and byte2, this returns - (byte1 | (byte2 << 8)). + /** Returns all the sub-text of a named child element. - If the stream is exhausted partway through reading the bytes, this will return zero. + If there is a child element with the given tag name, this will return + all of its sub-text (by calling getAllSubText() on it). If there is + no such child element, this will return the default string passed-in. - @see OutputStream::writeShort, readShortBigEndian + @see getAllSubText */ - virtual short readShort(); + const String getChildElementAllSubText (const tchar* const childTagName, + const String& defaultReturnValue) const throw(); - /** Reads two bytes from the stream as a little-endian 16-bit value. + /** Appends a section of text to this element. - If the next two bytes read are byte1 and byte2, this returns - (byte2 | (byte1 << 8)). + @see isTextElement, getText, getAllSubText + */ + void addTextElement (const String& text) throw(); - If the stream is exhausted partway through reading the bytes, this will return zero. + /** Removes all the text elements from this element. - @see OutputStream::writeShortBigEndian, readShort + @see isTextElement, getText, getAllSubText, addTextElement */ - virtual short readShortBigEndian(); + void deleteAllTextElements() throw(); - /** Reads four bytes from the stream as a little-endian 32-bit value. + /** Creates a text element that can be added to a parent element. + */ + static XmlElement* createTextElement (const String& text) throw(); - If the next four bytes are byte1 to byte4, this returns - (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)). + juce_UseDebuggingNewOperator - If the stream is exhausted partway through reading the bytes, this will return zero. +private: + friend class XmlDocument; - @see OutputStream::writeInt, readIntBigEndian - */ - virtual int readInt(); + String tagName; + XmlElement* firstChildElement; + XmlElement* nextElement; - /** Reads four bytes from the stream as a big-endian 32-bit value. + struct XmlAttributeNode + { + XmlAttributeNode (const XmlAttributeNode& other) throw(); + XmlAttributeNode (const String& name, const String& value) throw(); - If the next four bytes are byte1 to byte4, this returns - (byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)). + String name, value; + XmlAttributeNode* next; - If the stream is exhausted partway through reading the bytes, this will return zero. + private: + const XmlAttributeNode& operator= (const XmlAttributeNode&); + }; - @see OutputStream::writeIntBigEndian, readInt - */ - virtual int readIntBigEndian(); + XmlAttributeNode* attributes; - /** Reads eight bytes from the stream as a little-endian 64-bit value. + XmlElement (int) throw(); // for internal use + XmlElement (const tchar* const tagNameText, const int nameLen) throw(); - If the next eight bytes are byte1 to byte8, this returns - (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24) | (byte5 << 32) | (byte6 << 40) | (byte7 << 48) | (byte8 << 56)). + void copyChildrenAndAttributesFrom (const XmlElement& other) throw(); - If the stream is exhausted partway through reading the bytes, this will return zero. + void writeElementAsText (OutputStream& out, + const int indentationLevel, + const int lineWrapLength) const throw(); - @see OutputStream::writeInt64, readInt64BigEndian - */ - virtual int64 readInt64(); + void getChildElementsAsArray (XmlElement**) const throw(); + void reorderChildElements (XmlElement** const, const int) throw(); +}; - /** Reads eight bytes from the stream as a big-endian 64-bit value. +#endif // __JUCE_XMLELEMENT_JUCEHEADER__ +/********* End of inlined file: juce_XmlElement.h *********/ - If the next eight bytes are byte1 to byte8, this returns - (byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | (byte3 << 40) | (byte2 << 48) | (byte1 << 56)). +/** + A set of named property values, which can be strings, integers, floating point, etc. - If the stream is exhausted partway through reading the bytes, this will return zero. + Effectively, this just wraps a StringPairArray in an interface that makes it easier + to load and save types other than strings. - @see OutputStream::writeInt64BigEndian, readInt64 - */ - virtual int64 readInt64BigEndian(); + See the PropertiesFile class for a subclass of this, which automatically broadcasts change + messages and saves/loads the list from a file. +*/ +class JUCE_API PropertySet +{ +public: - /** Reads four bytes as a 32-bit floating point value. + /** Creates an empty PropertySet. - The raw 32-bit encoding of the float is read from the stream as a little-endian int. + @param ignoreCaseOfKeyNames if true, the names of properties are compared in a + case-insensitive way + */ + PropertySet (const bool ignoreCaseOfKeyNames = false) throw(); - If the stream is exhausted partway through reading the bytes, this will return zero. + /** Creates a copy of another PropertySet. + */ + PropertySet (const PropertySet& other) throw(); - @see OutputStream::writeFloat, readDouble + /** Copies another PropertySet over this one. */ - virtual float readFloat(); + const PropertySet& operator= (const PropertySet& other) throw(); - /** Reads four bytes as a 32-bit floating point value. + /** Destructor. */ + virtual ~PropertySet(); - The raw 32-bit encoding of the float is read from the stream as a big-endian int. + /** Returns one of the properties as a string. - If the stream is exhausted partway through reading the bytes, this will return zero. + If the value isn't found in this set, then this will look for it in a fallback + property set (if you've specified one with the setFallbackPropertySet() method), + and if it can't find one there, it'll return the default value passed-in. - @see OutputStream::writeFloatBigEndian, readDoubleBigEndian + @param keyName the name of the property to retrieve + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - virtual float readFloatBigEndian(); - - /** Reads eight bytes as a 64-bit floating point value. + const String getValue (const String& keyName, + const String& defaultReturnValue = String::empty) const throw(); - The raw 64-bit encoding of the double is read from the stream as a little-endian int64. + /** Returns one of the properties as an integer. - If the stream is exhausted partway through reading the bytes, this will return zero. + If the value isn't found in this set, then this will look for it in a fallback + property set (if you've specified one with the setFallbackPropertySet() method), + and if it can't find one there, it'll return the default value passed-in. - @see OutputStream::writeDouble, readFloat + @param keyName the name of the property to retrieve + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - virtual double readDouble(); - - /** Reads eight bytes as a 64-bit floating point value. + int getIntValue (const String& keyName, + const int defaultReturnValue = 0) const throw(); - The raw 64-bit encoding of the double is read from the stream as a big-endian int64. + /** Returns one of the properties as an double. - If the stream is exhausted partway through reading the bytes, this will return zero. + If the value isn't found in this set, then this will look for it in a fallback + property set (if you've specified one with the setFallbackPropertySet() method), + and if it can't find one there, it'll return the default value passed-in. - @see OutputStream::writeDoubleBigEndian, readFloatBigEndian + @param keyName the name of the property to retrieve + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - virtual double readDoubleBigEndian(); + double getDoubleValue (const String& keyName, + const double defaultReturnValue = 0.0) const throw(); - /** Reads an encoded 32-bit number from the stream using a space-saving compressed format. + /** Returns one of the properties as an boolean. - For small values, this is more space-efficient than using readInt() and OutputStream::writeInt() + The result will be true if the string found for this key name can be parsed as a non-zero + integer. - The format used is: number of significant bytes + up to 4 bytes in little-endian order. + If the value isn't found in this set, then this will look for it in a fallback + property set (if you've specified one with the setFallbackPropertySet() method), + and if it can't find one there, it'll return the default value passed-in. - @see OutputStream::writeCompressedInt() + @param keyName the name of the property to retrieve + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - virtual int readCompressedInt(); - - /** Reads a UTF8 string from the stream, up to the next linefeed or carriage return. - - This will read up to the next "\n" or "\r\n" or end-of-stream. + bool getBoolValue (const String& keyName, + const bool defaultReturnValue = false) const throw(); - After this call, the stream's position will be left pointing to the next character - following the line-feed, but the linefeeds aren't included in the string that - is returned. - */ - virtual const String readNextLine(); + /** Returns one of the properties as an XML element. - /** Reads a zero-terminated UTF8 string from the stream. + The result will a new XMLElement object that the caller must delete. If may return 0 if the + key isn't found, or if the entry contains an string that isn't valid XML. - This will read characters from the stream until it hits a zero character or - end-of-stream. + If the value isn't found in this set, then this will look for it in a fallback + property set (if you've specified one with the setFallbackPropertySet() method), + and if it can't find one there, it'll return the default value passed-in. - @see OutputStream::writeString, readEntireStreamAsString + @param keyName the name of the property to retrieve */ - virtual const String readString(); + XmlElement* getXmlValue (const String& keyName) const; - /** Tries to read the whole stream and turn it into a string. + /** Sets a named property as a string. - This will read from the stream's current position until the end-of-stream, and - will try to make an educated guess about whether it's unicode or an 8-bit encoding. + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to */ - virtual const String readEntireStreamAsString(); + void setValue (const String& keyName, const String& value) throw(); - /** Reads from the stream and appends the data to a MemoryBlock. + /** Sets a named property as a string. - @param destBlock the block to append the data onto - @param maxNumBytesToRead if this is a positive value, it sets a limit to the number - of bytes that will be read - if it's negative, data - will be read until the stream is exhausted. - @returns the number of bytes that were added to the memory block + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to */ - virtual int readIntoMemoryBlock (MemoryBlock& destBlock, - int maxNumBytesToRead = -1); + void setValue (const String& keyName, const tchar* const value) throw(); - /** Returns the offset of the next byte that will be read from the stream. + /** Sets a named property to an integer. - @see setPosition + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to */ - virtual int64 getPosition() = 0; + void setValue (const String& keyName, const int value) throw(); - /** Tries to move the current read position of the stream. + /** Sets a named property to a double. - The position is an absolute number of bytes from the stream's start. + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to + */ + void setValue (const String& keyName, const double value) throw(); - Some streams might not be able to do this, in which case they should do - nothing and return false. Others might be able to manage it by resetting - themselves and skipping to the correct position, although this is - obviously a bit slow. + /** Sets a named property to a boolean. - @returns true if the stream manages to reposition itself correctly - @see getPosition + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to */ - virtual bool setPosition (int64 newPosition) = 0; + void setValue (const String& keyName, const bool value) throw(); - /** Reads and discards a number of bytes from the stream. + /** Sets a named property to an XML element. - Some input streams might implement this efficiently, but the base - class will just keep reading data until the requisite number of bytes - have been done. + @param keyName the name of the property to set. (This mustn't be an empty string) + @param xml the new element to set it to. If this is zero, the value will be set to + an empty string + @see getXmlValue */ - virtual void skipNextBytes (int64 numBytesToSkip); + void setValue (const String& keyName, const XmlElement* const xml); - juce_UseDebuggingNewOperator + /** Deletes a property. -protected: + @param keyName the name of the property to delete. (This mustn't be an empty string) + */ + void removeValue (const String& keyName) throw(); - InputStream() throw() {} -}; + /** Returns true if the properies include the given key. */ + bool containsKey (const String& keyName) const throw(); -#endif // __JUCE_INPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_InputStream.h *********/ + /** Removes all values. */ + void clear(); -/** - The base class for streams that write data to some kind of destination. + /** Returns the keys/value pair array containing all the properties. */ + StringPairArray& getAllProperties() throw() { return properties; } - Input and output streams are used throughout the library - subclasses can override - some or all of the virtual functions to implement their behaviour. + /** Returns the lock used when reading or writing to this set */ + const CriticalSection& getLock() const throw() { return lock; } - @see InputStream, MemoryOutputStream, FileOutputStream -*/ -class JUCE_API OutputStream -{ -public: - /** Destructor. + /** Returns an XML element which encapsulates all the items in this property set. - Some subclasses might want to do things like call flush() during their - destructors. - */ - virtual ~OutputStream(); + The string parameter is the tag name that should be used for the node. - /** If the stream is using a buffer, this will ensure it gets written - out to the destination. */ - virtual void flush() = 0; + @see restoreFromXml + */ + XmlElement* createXml (const String& nodeName) const throw(); - /** Tries to move the stream's output position. + /** Reloads a set of properties that were previously stored as XML. - Not all streams will be able to seek to a new position - this will return - false if it fails to work. + The node passed in must have been created by the createXml() method. - @see getPosition + @see createXml */ - virtual bool setPosition (int64 newPosition) = 0; - - /** Returns the stream's current position. + void restoreFromXml (const XmlElement& xml) throw(); - @see setPosition - */ - virtual int64 getPosition() = 0; + /** Sets up a second PopertySet that will be used to look up any values that aren't + set in this one. - /** Writes a block of data to the stream. + If you set this up to be a pointer to a second property set, then whenever one + of the getValue() methods fails to find an entry in this set, it will look up that + value in the fallback set, and if it finds it, it will return that. - When creating a subclass of OutputStream, this is the only write method - that needs to be overloaded - the base class has methods for writing other - types of data which use this to do the work. + Make sure that you don't delete the fallback set while it's still being used by + another set! To remove the fallback set, just call this method with a null pointer. - @returns false if the write operation fails for some reason + @see getFallbackPropertySet */ - virtual bool write (const void* dataToWrite, - int howManyBytes) = 0; - - /** Writes a single byte to the stream. + void setFallbackPropertySet (PropertySet* fallbackProperties) throw(); - @see InputStream::readByte + /** Returns the fallback property set. + @see setFallbackPropertySet */ - virtual void writeByte (char byte); + PropertySet* getFallbackPropertySet() const throw() { return fallbackProperties; } - /** Writes a boolean to the stream. + juce_UseDebuggingNewOperator - This is encoded as a byte - either 1 or 0. +protected: - @see InputStream::readBool + /** Subclasses can override this to be told when one of the properies has been changed. */ - virtual void writeBool (bool boolValue); - - /** Writes a 16-bit integer to the stream in a little-endian byte order. + virtual void propertyChanged(); - This will write two bytes to the stream: (value & 0xff), then (value >> 8). +private: - @see InputStream::readShort - */ - virtual void writeShort (short value); + StringPairArray properties; + PropertySet* fallbackProperties; + CriticalSection lock; + bool ignoreCaseOfKeys; +}; - /** Writes a 16-bit integer to the stream in a big-endian byte order. +#endif // __JUCE_PROPERTYSET_JUCEHEADER__ +/********* End of inlined file: juce_PropertySet.h *********/ - This will write two bytes to the stream: (value >> 8), then (value & 0xff). +#endif +#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ - @see InputStream::readShortBigEndian - */ - virtual void writeShortBigEndian (short value); +/********* Start of inlined file: juce_ReferenceCountedArray.h *********/ +#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ +#define __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ - /** Writes a 32-bit integer to the stream in a little-endian byte order. +/********* Start of inlined file: juce_ReferenceCountedObject.h *********/ +#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ +#define __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ - @see InputStream::readInt - */ - virtual void writeInt (int value); +/********* Start of inlined file: juce_Atomic.h *********/ +#ifndef __JUCE_ATOMIC_JUCEHEADER__ +#define __JUCE_ATOMIC_JUCEHEADER__ - /** Writes a 32-bit integer to the stream in a big-endian byte order. +// Atomic increment/decrement operations.. - @see InputStream::readIntBigEndian - */ - virtual void writeIntBigEndian (int value); +#if (JUCE_MAC || JUCE_IPHONE) && ! DOXYGEN - /** Writes a 64-bit integer to the stream in a little-endian byte order. + #include + static forcedinline void atomicIncrement (int& variable) throw() { OSAtomicIncrement32 ((int32_t*) &variable); } + static forcedinline int atomicIncrementAndReturn (int& variable) throw() { return OSAtomicIncrement32 ((int32_t*) &variable); } + static forcedinline void atomicDecrement (int& variable) throw() { OSAtomicDecrement32 ((int32_t*) &variable); } + static forcedinline int atomicDecrementAndReturn (int& variable) throw() { return OSAtomicDecrement32 ((int32_t*) &variable); } - @see InputStream::readInt64 - */ - virtual void writeInt64 (int64 value); +#elif JUCE_GCC - /** Writes a 64-bit integer to the stream in a big-endian byte order. + #if JUCE_USE_GCC_ATOMIC_INTRINSICS + forcedinline void atomicIncrement (int& variable) throw() { __sync_add_and_fetch (&variable, 1); } + forcedinline int atomicIncrementAndReturn (int& variable) throw() { return __sync_add_and_fetch (&variable, 1); } + forcedinline void atomicDecrement (int& variable) throw() { __sync_add_and_fetch (&variable, -1); } + forcedinline int atomicDecrementAndReturn (int& variable) throw() { return __sync_add_and_fetch (&variable, -1); } + #else - @see InputStream::readInt64BigEndian - */ - virtual void writeInt64BigEndian (int64 value); + /** Increments an integer in a thread-safe way. */ + forcedinline void atomicIncrement (int& variable) throw() + { + __asm__ __volatile__ ( + #if JUCE_64BIT + "lock incl (%%rax)" + : + : "a" (&variable) + : "cc", "memory"); + #else + "lock incl %0" + : "=m" (variable) + : "m" (variable)); + #endif + } - /** Writes a 32-bit floating point value to the stream. + /** Increments an integer in a thread-safe way and returns the incremented value. */ + forcedinline int atomicIncrementAndReturn (int& variable) throw() + { + int result; - The binary 32-bit encoding of the float is written as a little-endian int. + __asm__ __volatile__ ( + #if JUCE_64BIT + "lock xaddl %%ebx, (%%rax) \n\ + incl %%ebx" + : "=b" (result) + : "a" (&variable), "b" (1) + : "cc", "memory"); + #else + "lock xaddl %%eax, (%%ecx) \n\ + incl %%eax" + : "=a" (result) + : "c" (&variable), "a" (1) + : "memory"); + #endif - @see InputStream::readFloat - */ - virtual void writeFloat (float value); + return result; + } - /** Writes a 32-bit floating point value to the stream. + /** Decrememts an integer in a thread-safe way. */ + forcedinline void atomicDecrement (int& variable) throw() + { + __asm__ __volatile__ ( + #if JUCE_64BIT + "lock decl (%%rax)" + : + : "a" (&variable) + : "cc", "memory"); + #else + "lock decl %0" + : "=m" (variable) + : "m" (variable)); + #endif + } - The binary 32-bit encoding of the float is written as a big-endian int. + /** Decrememts an integer in a thread-safe way and returns the incremented value. */ + forcedinline int atomicDecrementAndReturn (int& variable) throw() + { + int result; - @see InputStream::readFloatBigEndian - */ - virtual void writeFloatBigEndian (float value); + __asm__ __volatile__ ( + #if JUCE_64BIT + "lock xaddl %%ebx, (%%rax) \n\ + decl %%ebx" + : "=b" (result) + : "a" (&variable), "b" (-1) + : "cc", "memory"); + #else + "lock xaddl %%eax, (%%ecx) \n\ + decl %%eax" + : "=a" (result) + : "c" (&variable), "a" (-1) + : "memory"); + #endif + return result; + } + #endif - /** Writes a 64-bit floating point value to the stream. +#elif JUCE_USE_INTRINSICS - The eight raw bytes of the double value are written out as a little-endian 64-bit int. + #pragma intrinsic (_InterlockedIncrement) + #pragma intrinsic (_InterlockedDecrement) - @see InputStream::readDouble - */ - virtual void writeDouble (double value); + /** Increments an integer in a thread-safe way. */ + forcedinline void __fastcall atomicIncrement (int& variable) throw() + { + _InterlockedIncrement (reinterpret_cast (&variable)); + } - /** Writes a 64-bit floating point value to the stream. + /** Increments an integer in a thread-safe way and returns the incremented value. */ + forcedinline int __fastcall atomicIncrementAndReturn (int& variable) throw() + { + return _InterlockedIncrement (reinterpret_cast (&variable)); + } - The eight raw bytes of the double value are written out as a big-endian 64-bit int. + /** Decrememts an integer in a thread-safe way. */ + forcedinline void __fastcall atomicDecrement (int& variable) throw() + { + _InterlockedDecrement (reinterpret_cast (&variable)); + } - @see InputStream::readDoubleBigEndian - */ - virtual void writeDoubleBigEndian (double value); + /** Decrememts an integer in a thread-safe way and returns the incremented value. */ + forcedinline int __fastcall atomicDecrementAndReturn (int& variable) throw() + { + return _InterlockedDecrement (reinterpret_cast (&variable)); + } +#else - /** Writes a condensed encoding of a 32-bit integer. + /** Increments an integer in a thread-safe way. */ + forcedinline void __fastcall atomicIncrement (int& variable) throw() + { + __asm { + mov ecx, dword ptr [variable] + lock inc dword ptr [ecx] + } + } - If you're storing a lot of integers which are unlikely to have very large values, - this can save a lot of space, because values under 0xff will only take up 2 bytes, - under 0xffff only 3 bytes, etc. + /** Increments an integer in a thread-safe way and returns the incremented value. */ + forcedinline int __fastcall atomicIncrementAndReturn (int& variable) throw() + { + int result; - The format used is: number of significant bytes + up to 4 bytes in little-endian order. + __asm { + mov ecx, dword ptr [variable] + mov eax, 1 + lock xadd dword ptr [ecx], eax + inc eax + mov result, eax + } - @see InputStream::readCompressedInt - */ - virtual void writeCompressedInt (int value); + return result; + } - /** Stores a string in the stream. + /** Decrememts an integer in a thread-safe way. */ + forcedinline void __fastcall atomicDecrement (int& variable) throw() + { + __asm { + mov ecx, dword ptr [variable] + lock dec dword ptr [ecx] + } + } - This isn't the method to use if you're trying to append text to the end of a - text-file! It's intended for storing a string for later retrieval - by InputStream::readString. + /** Decrememts an integer in a thread-safe way and returns the incremented value. */ + forcedinline int __fastcall atomicDecrementAndReturn (int& variable) throw() + { + int result; - It writes the string to the stream as UTF8, with a null character terminating it. + __asm { + mov ecx, dword ptr [variable] + mov eax, -1 + lock xadd dword ptr [ecx], eax + dec eax + mov result, eax + } - For appending text to a file, instead use writeText, printf, or operator<< + return result; + } +#endif - @see InputStream::readString, writeText, printf, operator<< - */ - virtual void writeString (const String& text); +#endif // __JUCE_ATOMIC_JUCEHEADER__ +/********* End of inlined file: juce_Atomic.h *********/ - /** Writes a string of text to the stream. +/** + Adds reference-counting to an object. - It can either write it as 8-bit system-encoded characters, or as unicode, and - can also add unicode header bytes (0xff, 0xfe) to indicate the endianness (this - should only be done at the start of a file). + To add reference-counting to a class, derive it from this class, and + use the ReferenceCountedObjectPtr class to point to it. - The method also replaces '\\n' characters in the text with '\\r\\n'. - */ - virtual void writeText (const String& text, - const bool asUnicode, - const bool writeUnicodeHeaderBytes); + e.g. @code + class MyClass : public ReferenceCountedObject + { + void foo(); - /** Writes a string of text to the stream. + // This is a neat way of declaring a typedef for a pointer class, + // rather than typing out the full templated name each time.. + typedef ReferenceCountedObjectPtr Ptr; + }; - @see writeText - */ - virtual void printf (const char* format, ...); + MyClass::Ptr p = new MyClass(); + MyClass::Ptr p2 = p; + p = 0; + p2->foo(); + @endcode - /** Reads data from an input stream and writes it to this stream. + Once a new ReferenceCountedObject has been assigned to a pointer, be + careful not to delete the object manually. - @param source the stream to read from - @param maxNumBytesToWrite the number of bytes to read from the stream (if this is - less than zero, it will keep reading until the input - is exhausted) - */ - virtual int writeFromInputStream (InputStream& source, - int maxNumBytesToWrite); + @see ReferenceCountedObjectPtr, ReferenceCountedArray +*/ +class JUCE_API ReferenceCountedObject +{ +public: - /** Writes a number to the stream as 8-bit characters in the default system encoding. */ - virtual OutputStream& operator<< (const int number); + /** Increments the object's reference count. - /** Writes a number to the stream as 8-bit characters in the default system encoding. */ - virtual OutputStream& operator<< (const double number); + This is done automatically by the smart pointer, but is public just + in case it's needed for nefarious purposes. + */ + inline void incReferenceCount() throw() + { + atomicIncrement (refCounts); - /** Writes a character to the stream. */ - virtual OutputStream& operator<< (const char character); + jassert (refCounts > 0); + } - /** Writes a null-terminated string to the stream. */ - virtual OutputStream& operator<< (const char* const text); + /** Decreases the object's reference count. - /** Writes a null-terminated unicode text string to the stream, converting it - to 8-bit characters in the default system encoding. */ - virtual OutputStream& operator<< (const juce_wchar* const text); + If the count gets to zero, the object will be deleted. + */ + inline void decReferenceCount() throw() + { + jassert (refCounts > 0); - /** Writes a string to the stream as 8-bit characters in the default system encoding. */ - virtual OutputStream& operator<< (const String& text); + if (atomicDecrementAndReturn (refCounts) == 0) + delete this; + } - juce_UseDebuggingNewOperator + /** Returns the object's current reference count. */ + inline int getReferenceCount() const throw() + { + return refCounts; + } protected: - OutputStream() throw(); -}; + /** Creates the reference-counted object (with an initial ref count of zero). */ + ReferenceCountedObject() + : refCounts (0) + { + } -#endif // __JUCE_OUTPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_OutputStream.h *********/ + /** Destructor. */ + virtual ~ReferenceCountedObject() + { + // it's dangerous to delete an object that's still referenced by something else! + jassert (refCounts == 0); + } -class JUCE_API DynamicObject; +private: + + int refCounts; +}; /** - A variant class, that can be used to hold a range of primitive values. + Used to point to an object of type ReferenceCountedObject. - A var object can hold a range of simple primitive values, strings, or - a reference-counted pointer to a DynamicObject. The var class is intended - to act like the values used in dynamic scripting languages. + It's wise to use a typedef instead of typing out the templated name + each time - e.g. - @see DynamicObject + typedef ReferenceCountedObjectPtr MyClassPtr; + + @see ReferenceCountedObject, ReferenceCountedObjectArray */ -class JUCE_API var +template +class ReferenceCountedObjectPtr { public: - typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments); - - /** Creates a void variant. */ - var() throw(); + /** Creates a pointer to a null object. */ + inline ReferenceCountedObjectPtr() throw() + : referencedObject (0) + { + } - /** Destructor. */ - ~var(); + /** Creates a pointer to an object. - var (const var& valueToCopy) throw(); - var (const int value) throw(); - var (const bool value) throw(); - var (const double value) throw(); - var (const char* const value) throw(); - var (const juce_wchar* const value) throw(); - var (const String& value) throw(); - var (DynamicObject* const object) throw(); - var (MethodFunction method) throw(); + This will increment the object's reference-count if it is non-null. + */ + inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) throw() + : referencedObject (refCountedObject) + { + if (refCountedObject != 0) + refCountedObject->incReferenceCount(); + } - const var& operator= (const var& valueToCopy) throw(); - const var& operator= (const int value) throw(); - const var& operator= (const bool value) throw(); - const var& operator= (const double value) throw(); - const var& operator= (const char* const value) throw(); - const var& operator= (const juce_wchar* const value) throw(); - const var& operator= (const String& value) throw(); - const var& operator= (DynamicObject* const object) throw(); - const var& operator= (MethodFunction method) throw(); + /** Copies another pointer. - operator int() const throw(); - operator bool() const throw(); - operator float() const throw(); - operator double() const throw(); - operator const String() const throw(); - const String toString() const throw(); - DynamicObject* getObject() const throw(); - - bool isVoid() const throw() { return type == voidType; } - bool isInt() const throw() { return type == intType; } - bool isBool() const throw() { return type == boolType; } - bool isDouble() const throw() { return type == doubleType; } - bool isString() const throw() { return type == stringType; } - bool isObject() const throw() { return type == objectType; } - bool isMethod() const throw() { return type == methodType; } - - bool operator== (const var& other) const throw(); - bool operator!= (const var& other) const throw(); - - /** Writes a binary representation of this value to a stream. - The data can be read back later using readFromStream(). + This will increment the object's reference-count (if it is non-null). */ - void writeToStream (OutputStream& output) const throw(); + inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) throw() + : referencedObject (other.referencedObject) + { + if (referencedObject != 0) + referencedObject->incReferenceCount(); + } - /** Reads back a stored binary representation of a value. - The data in the stream must have been written using writeToStream(), or this - will have unpredictable results. - */ - static const var readFromStream (InputStream& input) throw(); + /** Changes this pointer to point at a different object. - class JUCE_API identifier + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + */ + const ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) { - public: - identifier (const char* const name) throw(); - identifier (const String& name) throw(); - ~identifier() throw(); + ReferenceCountedObjectClass* const newObject = other.referencedObject; - bool operator== (const identifier& other) const throw() + if (newObject != referencedObject) { - jassert (hashCode != other.hashCode || name == other.name); // check for name hash collisions - return hashCode == other.hashCode; + if (newObject != 0) + newObject->incReferenceCount(); + + ReferenceCountedObjectClass* const oldObject = referencedObject; + referencedObject = newObject; + + if (oldObject != 0) + oldObject->decReferenceCount(); } - String name; - int hashCode; - }; + return *this; + } - /** If this variant is an object, this returns one of its properties. */ - const var operator[] (const identifier& propertyName) const throw(); + /** Changes this pointer to point at a different object. - /** If this variant is an object, this invokes one of its methods with no arguments. */ - const var call (const identifier& method) const; - /** If this variant is an object, this invokes one of its methods with one argument. */ - const var call (const identifier& method, const var& arg1) const; - /** If this variant is an object, this invokes one of its methods with 2 arguments. */ - const var call (const identifier& method, const var& arg1, const var& arg2) const; - /** If this variant is an object, this invokes one of its methods with 3 arguments. */ - const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3); - /** If this variant is an object, this invokes one of its methods with 4 arguments. */ - const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; - /** If this variant is an object, this invokes one of its methods with 5 arguments. */ - const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; + The reference count of the old object is decremented, and it might be + deleted if it hits zero. The new object's count is incremented. + */ + const ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject) + { + if (referencedObject != newObject) + { + if (newObject != 0) + newObject->incReferenceCount(); - /** If this variant is an object, this invokes one of its methods with a list of arguments. */ - const var invoke (const identifier& method, const var* arguments, int numArguments) const; + ReferenceCountedObjectClass* const oldObject = referencedObject; + referencedObject = newObject; - /** If this variant is a method pointer, this invokes it on a target object. */ - const var invoke (const var& targetObject, const var* arguments, int numArguments) const; + if (oldObject != 0) + oldObject->decReferenceCount(); + } - juce_UseDebuggingNewOperator + return *this; + } -private: - enum Type + /** Destructor. + + This will decrement the object's reference-count, and may delete it if it + gets to zero. + */ + inline ~ReferenceCountedObjectPtr() { - voidType = 0, - intType, - boolType, - doubleType, - stringType, - objectType, - methodType - }; + if (referencedObject != 0) + referencedObject->decReferenceCount(); + } - Type type; + /** Returns the object that this pointer references. - union + The pointer returned may be zero, of course. + */ + inline operator ReferenceCountedObjectClass*() const throw() { - int intValue; - bool boolValue; - double doubleValue; - String* stringValue; - DynamicObject* objectValue; - MethodFunction methodValue; - } value; + return referencedObject; + } - void releaseValue() throw(); + /** Returns true if this pointer refers to the given object. */ + inline bool operator== (ReferenceCountedObjectClass* const object) const throw() + { + return referencedObject == object; + } + + /** Returns true if this pointer doesn't refer to the given object. */ + inline bool operator!= (ReferenceCountedObjectClass* const object) const throw() + { + return referencedObject != object; + } + + // the -> operator is called on the referenced object + inline ReferenceCountedObjectClass* operator->() const throw() + { + return referencedObject; + } + +private: + + ReferenceCountedObjectClass* referencedObject; }; +#endif // __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ +/********* End of inlined file: juce_ReferenceCountedObject.h *********/ + /** - Represents a dynamically implemented object. + Holds a list of objects derived from ReferenceCountedObject. - An instance of this class can be used to store named properties, and - by subclassing hasMethod() and invokeMethod(), you can give your object - methods. + A ReferenceCountedArray holds objects derived from ReferenceCountedObject, + and takes care of incrementing and decrementing their ref counts when they + are added and removed from the array. - This is intended for use as a wrapper for scripting language objects. + To make all the array's methods thread-safe, pass in "CriticalSection" as the templated + TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. + + @see Array, OwnedArray, StringArray */ -class JUCE_API DynamicObject : public ReferenceCountedObject +template +class ReferenceCountedArray { public: - DynamicObject(); - - /** Destructor. */ - virtual ~DynamicObject(); - - /** Returns true if the object has a property with this name. - Note that if the property is actually a method, this will return false. - */ - virtual bool hasProperty (const var::identifier& propertyName) const; + /** Creates an empty array. - /** Returns a named property. + @param granularity this is the size of increment by which the internal storage + used by the array will grow. Only change it from the default if you know the + array is going to be very big and needs to be able to grow efficiently. - This returns a void if no such property exists. + @see ReferenceCountedObject, Array, OwnedArray */ - virtual const var getProperty (const var::identifier& propertyName) const; - - /** Sets a named property. */ - virtual void setProperty (const var::identifier& propertyName, const var& newValue); - - /** Removes a named property. */ - virtual void removeProperty (const var::identifier& propertyName); + ReferenceCountedArray (const int granularity = juceDefaultArrayGranularity) throw() + : data (granularity), + numUsed (0) + { + } - /** Checks whether this object has the specified method. + /** Creates a copy of another array */ + ReferenceCountedArray (const ReferenceCountedArray& other) throw() + : data (other.data.granularity) + { + other.lockArray(); + numUsed = other.numUsed; + data.setAllocatedSize (numUsed); + memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); - The default implementation of this just checks whether there's a property - with this name that's actually a method, but this can be overridden for - building objects with dynamic invocation. - */ - virtual bool hasMethod (const var::identifier& methodName) const; + for (int i = numUsed; --i >= 0;) + if (data.elements[i] != 0) + data.elements[i]->incReferenceCount(); - /** Invokes a named method on this object. + other.unlockArray(); + } - The default implementation looks up the named property, and if it's a method - call, then it invokes it. + /** Copies another array into this one. - This method is virtual to allow more dynamic invocation to used for objects - where the methods may not already be set as properies. + Any existing objects in this array will first be released. */ - virtual const var invokeMethod (const var::identifier& methodName, - const var* parameters, - int numParameters); + const ReferenceCountedArray& operator= (const ReferenceCountedArray& other) throw() + { + if (this != &other) + { + other.lockArray(); + lock.enter(); - /** Sets up a method. + clear(); - This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but - helps to avoid accidentally invoking the wrong type of var constructor. It also makes - the code easier to read, + data.granularity = other.granularity; + data.ensureAllocatedSize (other.numUsed); + numUsed = other.numUsed; + memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); + minimiseStorageOverheads(); - The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g. - @code - setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething); - @endcode - */ - void setMethod (const var::identifier& methodName, - var::MethodFunction methodFunction); + for (int i = numUsed; --i >= 0;) + if (data.elements[i] != 0) + data.elements[i]->incReferenceCount(); - /** Removes all properties and methods from the object. */ - void clear(); + lock.exit(); + other.unlockArray(); + } - juce_UseDebuggingNewOperator + return *this; + } -private: - Array propertyIds; - OwnedArray propertyValues; -}; + /** Destructor. -#endif // __JUCE_VARIANT_JUCEHEADER__ -/********* End of inlined file: juce_Variant.h *********/ + Any objects in the array will be released, and may be deleted if not referenced from elsewhere. + */ + ~ReferenceCountedArray() + { + clear(); + } -#endif -#ifndef __JUCE_BITARRAY_JUCEHEADER__ + /** Removes all objects from the array. -#endif -#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ + Any objects in the array that are not referenced from elsewhere will be deleted. + */ + void clear() + { + lock.enter(); -#endif -#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ + while (numUsed > 0) + if (data.elements [--numUsed] != 0) + data.elements [numUsed]->decReferenceCount(); -#endif -#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ + jassert (numUsed == 0); + data.setAllocatedSize (0); -#endif -#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ + lock.exit(); + } -/********* Start of inlined file: juce_PropertySet.h *********/ -#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ -#define __JUCE_PROPERTYSET_JUCEHEADER__ + /** Returns the current number of objects in the array. */ + inline int size() const throw() + { + return numUsed; + } -/********* Start of inlined file: juce_StringPairArray.h *********/ -#ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ -#define __JUCE_STRINGPAIRARRAY_JUCEHEADER__ + /** Returns a pointer to the object at this index in the array. -/** - A container for holding a set of strings which are keyed by another string. + If the index is out-of-range, this will return a null pointer, (and + it could be null anyway, because it's ok for the array to hold null + pointers as well as objects). - @see StringArray -*/ -class JUCE_API StringPairArray -{ -public: + @see getUnchecked + */ + inline const ReferenceCountedObjectPtr operator[] (const int index) const throw() + { + lock.enter(); + const ReferenceCountedObjectPtr result ((((unsigned int) index) < (unsigned int) numUsed) + ? data.elements [index] + : (ObjectClass*) 0); + lock.exit(); + return result; + } - /** Creates an empty array */ - StringPairArray (const bool ignoreCaseWhenComparingKeys = true) throw(); + /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. - /** Creates a copy of another array */ - StringPairArray (const StringPairArray& other) throw(); + This is a faster and less safe version of operator[] which doesn't check the index passed in, so + it can be used when you're sure the index if always going to be legal. + */ + inline const ReferenceCountedObjectPtr getUnchecked (const int index) const throw() + { + lock.enter(); + jassert (((unsigned int) index) < (unsigned int) numUsed); + const ReferenceCountedObjectPtr result (data.elements [index]); + lock.exit(); + return result; + } - /** Destructor. */ - ~StringPairArray() throw(); + /** Returns a pointer to the first object in the array. - /** Copies the contents of another string array into this one */ - const StringPairArray& operator= (const StringPairArray& other) throw(); + This will return a null pointer if the array's empty. + @see getLast + */ + inline const ReferenceCountedObjectPtr getFirst() const throw() + { + lock.enter(); + const ReferenceCountedObjectPtr result ((numUsed > 0) ? data.elements [0] + : (ObjectClass*) 0); + lock.exit(); - /** Compares two arrays. + return result; + } - Comparisons are case-sensitive. + /** Returns a pointer to the last object in the array. - @returns true only if the other array contains exactly the same strings with the same keys + This will return a null pointer if the array's empty. + @see getFirst */ - bool operator== (const StringPairArray& other) const throw(); + inline const ReferenceCountedObjectPtr getLast() const throw() + { + lock.enter(); + const ReferenceCountedObjectPtr result ((numUsed > 0) ? data.elements [numUsed - 1] + : (ObjectClass*) 0); + lock.exit(); - /** Compares two arrays. + return result; + } - Comparisons are case-sensitive. + /** Finds the index of the first occurrence of an object in the array. - @returns false if the other array contains exactly the same strings with the same keys + @param objectToLookFor the object to look for + @returns the index at which the object was found, or -1 if it's not found */ - bool operator!= (const StringPairArray& other) const throw(); - - /** Finds the value corresponding to a key string. + int indexOf (const ObjectClass* const objectToLookFor) const throw() + { + int result = -1; - If no such key is found, this will just return an empty string. To check whether - a given key actually exists (because it might actually be paired with an empty string), use - the getAllKeys() method to obtain a list. + lock.enter(); + ObjectClass** e = data.elements; - Obviously the reference returned shouldn't be stored for later use, as the - string it refers to may disappear when the array changes. + for (int i = numUsed; --i >= 0;) + { + if (objectToLookFor == *e) + { + result = (int) (e - data.elements); + break; + } - @see getValue - */ - const String& operator[] (const String& key) const throw(); + ++e; + } - /** Finds the value corresponding to a key string. + lock.exit(); + return result; + } - If no such key is found, this will just return the value provided as a default. + /** Returns true if the array contains a specified object. - @see operator[] + @param objectToLookFor the object to look for + @returns true if the object is in the array */ - const String getValue (const String& key, const String& defaultReturnValue) const; - - /** Returns a list of all keys in the array. */ - const StringArray& getAllKeys() const throw() { return keys; } + bool contains (const ObjectClass* const objectToLookFor) const throw() + { + lock.enter(); + ObjectClass** e = data.elements; - /** Returns a list of all values in the array. */ - const StringArray& getAllValues() const throw() { return values; } + for (int i = numUsed; --i >= 0;) + { + if (objectToLookFor == *e) + { + lock.exit(); + return true; + } - /** Returns the number of strings in the array */ - inline int size() const throw() { return keys.size(); }; + ++e; + } - /** Adds or amends a key/value pair. + lock.exit(); + return false; + } - If a value already exists with this key, its value will be overwritten, - otherwise the key/value pair will be added to the array. - */ - void set (const String& key, - const String& value) throw(); + /** Appends a new object to the end of the array. - /** Adds the items from another array to this one. + This will increase the new object's reference count. - This is equivalent to using set() to add each of the pairs from the other array. + @param newObject the new object to add to the array + @see set, insert, addIfNotAlreadyThere, addSorted, addArray */ - void addArray (const StringPairArray& other); + void add (ObjectClass* const newObject) throw() + { + lock.enter(); + data.ensureAllocatedSize (numUsed + 1); + data.elements [numUsed++] = newObject; - /** Removes all elements from the array. */ - void clear() throw(); + if (newObject != 0) + newObject->incReferenceCount(); - /** Removes a string from the array based on its key. + lock.exit(); + } - If the key isn't found, nothing will happen. - */ - void remove (const String& key) throw(); + /** Inserts a new object into the array at the given index. - /** Removes a string from the array based on its index. + If the index is less than 0 or greater than the size of the array, the + element will be added to the end of the array. + Otherwise, it will be inserted into the array, moving all the later elements + along to make room. - If the index is out-of-range, no action will be taken. - */ - void remove (const int index) throw(); + This will increase the new object's reference count. - /** Indicates whether to use a case-insensitive search when looking up a key string. + @param indexToInsertAt the index at which the new element should be inserted + @param newObject the new object to add to the array + @see add, addSorted, addIfNotAlreadyThere, set */ - void setIgnoresCase (const bool shouldIgnoreCase) throw(); + void insert (int indexToInsertAt, + ObjectClass* const newObject) throw() + { + if (indexToInsertAt >= 0) + { + lock.enter(); - /** Returns a descriptive string containing the items. + if (indexToInsertAt > numUsed) + indexToInsertAt = numUsed; - This is handy for dumping the contents of an array. - */ - const String getDescription() const; + data.ensureAllocatedSize (numUsed + 1); - /** Reduces the amount of storage being used by the array. + ObjectClass** const e = data.elements + indexToInsertAt; + const int numToMove = numUsed - indexToInsertAt; - Arrays typically allocate slightly more storage than they need, and after - removing elements, they may have quite a lot of unused space allocated. - This method will reduce the amount of allocated storage to a minimum. - */ - void minimiseStorageOverheads() throw(); + if (numToMove > 0) + memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); - juce_UseDebuggingNewOperator + *e = newObject; -private: - StringArray keys, values; - bool ignoreCase; -}; + if (newObject != 0) + newObject->incReferenceCount(); -#endif // __JUCE_STRINGPAIRARRAY_JUCEHEADER__ -/********* End of inlined file: juce_StringPairArray.h *********/ - -/********* Start of inlined file: juce_XmlElement.h *********/ -#ifndef __JUCE_XMLELEMENT_JUCEHEADER__ -#define __JUCE_XMLELEMENT_JUCEHEADER__ - -/** A handy macro to make it easy to iterate all the child elements in an XmlElement. + ++numUsed; + lock.exit(); + } + else + { + add (newObject); + } + } - The parentXmlElement should be a reference to the parent XML, and the childElementVariableName - will be the name of a pointer to each child element. + /** Appends a new object at the end of the array as long as the array doesn't + already contain it. - E.g. @code - XmlElement* myParentXml = createSomeKindOfXmlDocument(); + If the array already contains a matching object, nothing will be done. - forEachXmlChildElement (*myParentXml, child) + @param newObject the new object to add to the array + */ + void addIfNotAlreadyThere (ObjectClass* const newObject) throw() { - if (child->hasTagName ("FOO")) - doSomethingWithXmlElement (child); - } - - @endcode + lock.enter(); - @see forEachXmlChildElementWithTagName -*/ -#define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ -\ - for (XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \ - childElementVariableName != 0; \ - childElementVariableName = childElementVariableName->getNextElement()) + if (! contains (newObject)) + add (newObject); -/** A macro that makes it easy to iterate all the child elements of an XmlElement - which have a specified tag. + lock.exit(); + } - This does the same job as the forEachXmlChildElement macro, but only for those - elements that have a particular tag name. + /** Replaces an object in the array with a different one. - The parentXmlElement should be a reference to the parent XML, and the childElementVariableName - will be the name of a pointer to each child element. The requiredTagName is the - tag name to match. + If the index is less than zero, this method does nothing. + If the index is beyond the end of the array, the new object is added to the end of the array. - E.g. @code - XmlElement* myParentXml = createSomeKindOfXmlDocument(); + The object being added has its reference count increased, and if it's replacing + another object, then that one has its reference count decreased, and may be deleted. - forEachXmlChildElementWithTagName (*myParentXml, child, T("MYTAG")) + @param indexToChange the index whose value you want to change + @param newObject the new value to set for this index. + @see add, insert, remove + */ + void set (const int indexToChange, + ObjectClass* const newObject) { - // the child object is now guaranteed to be a element.. - doSomethingWithMYTAGElement (child); - } + if (indexToChange >= 0) + { + lock.enter(); - @endcode + if (newObject != 0) + newObject->incReferenceCount(); - @see forEachXmlChildElement -*/ -#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ -\ - for (XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \ - childElementVariableName != 0; \ - childElementVariableName = childElementVariableName->getNextElementWithTagName (requiredTagName)) + if (indexToChange < numUsed) + { + if (data.elements [indexToChange] != 0) + data.elements [indexToChange]->decReferenceCount(); -/** Used to build a tree of elements representing an XML document. + data.elements [indexToChange] = newObject; + } + else + { + data.ensureAllocatedSize (numUsed + 1); + data.elements [numUsed++] = newObject; + } - An XML document can be parsed into a tree of XmlElements, each of which - represents an XML tag structure, and which may itself contain other - nested elements. + lock.exit(); + } + } - An XmlElement can also be converted back into a text document, and has - lots of useful methods for manipulating its attributes and sub-elements, - so XmlElements can actually be used as a handy general-purpose data - structure. + /** Adds elements from another array to the end of this array. - Here's an example of parsing some elements: @code - // check we're looking at the right kind of document.. - if (myElement->hasTagName ("ANIMALS")) + @param arrayToAddFrom the array from which to copy the elements + @param startIndex the first element of the other array to start copying from + @param numElementsToAdd how many elements to add from the other array. If this + value is negative or greater than the number of available elements, + all available elements will be copied. + @see add + */ + void addArray (const ReferenceCountedArray& arrayToAddFrom, + int startIndex = 0, + int numElementsToAdd = -1) throw() { - // now we'll iterate its sub-elements looking for 'giraffe' elements.. - forEachXmlChildElement (*myElement, e) - { - if (e->hasTagName ("GIRAFFE")) - { - // found a giraffe, so use some of its attributes.. + arrayToAddFrom.lockArray(); + lock.enter(); - String giraffeName = e->getStringAttribute ("name"); - int giraffeAge = e->getIntAttribute ("age"); - bool isFriendly = e->getBoolAttribute ("friendly"); - } + if (startIndex < 0) + { + jassertfalse + startIndex = 0; } - } - @endcode - And here's an example of how to create an XML document from scratch: @code - // create an outer node called "ANIMALS" - XmlElement animalsList ("ANIMALS"); + if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) + numElementsToAdd = arrayToAddFrom.size() - startIndex; - for (int i = 0; i < numAnimals; ++i) - { - // create an inner element.. - XmlElement* giraffe = new XmlElement ("GIRAFFE"); + if (numElementsToAdd > 0) + { + data.ensureAllocatedSize (numUsed + numElementsToAdd); - giraffe->setAttribute ("name", "nigel"); - giraffe->setAttribute ("age", 10); - giraffe->setAttribute ("friendly", true); + while (--numElementsToAdd >= 0) + add (arrayToAddFrom.getUnchecked (startIndex++)); + } - // ..and add our new element to the parent node - animalsList.addChildElement (giraffe); + lock.exit(); + arrayToAddFrom.unlockArray(); } - // now we can turn the whole thing into a text document.. - String myXmlDoc = animalsList.createDocument (String::empty); - @endcode + /** Inserts a new object into the array assuming that the array is sorted. - @see XmlDocument -*/ -class JUCE_API XmlElement -{ -public: + This will use a comparator to find the position at which the new object + should go. If the array isn't sorted, the behaviour of this + method will be unpredictable. - /** Creates an XmlElement with this tag name. */ - XmlElement (const String& tagName) throw(); + @param comparator the comparator object to use to compare the elements - see the + sort() method for details about this object's form + @param newObject the new object to insert to the array + @see add, sort + */ + template + void addSorted (ElementComparator& comparator, + ObjectClass* newObject) throw() + { + lock.enter(); + insert (findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed), newObject); + lock.exit(); + } - /** Creates a (deep) copy of another element. */ - XmlElement (const XmlElement& other) throw(); + /** Inserts or replaces an object in the array, assuming it is sorted. - /** Creates a (deep) copy of another element. */ - const XmlElement& operator= (const XmlElement& other) throw(); + This is similar to addSorted, but if a matching element already exists, then it will be + replaced by the new one, rather than the new one being added as well. + */ + template + void addOrReplaceSorted (ElementComparator& comparator, + ObjectClass* newObject) throw() + { + lock.enter(); + const int index = findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed); - /** Deleting an XmlElement will also delete all its child elements. */ - ~XmlElement() throw(); + if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0) + set (index - 1, newObject); // replace an existing object that matches + else + insert (index, newObject); // no match, so insert the new one - /** Compares two XmlElements to see if they contain the same text and attiributes. + lock.exit(); + } - The elements are only considered equivalent if they contain the same attiributes - with the same values, and have the same sub-nodes. + /** Removes an object from the array. - @param other the other element to compare to - @param ignoreOrderOfAttributes if true, this means that two elements with the - same attributes in a different order will be - considered the same; if false, the attributes must - be in the same order as well - */ - bool isEquivalentTo (const XmlElement* const other, - const bool ignoreOrderOfAttributes) const throw(); + This will remove the object at a given index and move back all the + subsequent objects to close the gap. - /** Returns an XML text document that represents this element. + If the index passed in is out-of-range, nothing will happen. - The string returned can be parsed to recreate the same XmlElement that - was used to create it. + The object that is removed will have its reference count decreased, + and may be deleted if not referenced from elsewhere. - @param dtdToUse the DTD to add to the document - @param allOnOneLine if true, this means that the document will not contain any - linefeeds, so it'll be smaller but not very easy to read. - @param includeXmlHeader whether to add the "decReferenceCount(); - /** Writes the element to a file as an XML document. + --numUsed; + const int numberToShift = numUsed - indexToRemove; - To improve safety in case something goes wrong while writing the file, this - will actually write the document to a new temporary file in the same - directory as the destination file, and if this succeeds, it will rename this - new file as the destination file (overwriting any existing file that was there). + if (numberToShift > 0) + memmove (e, e + 1, numberToShift * sizeof (ObjectClass*)); - @param destinationFile the file to write to. If this already exists, it will be - overwritten. - @param dtdToUse the DTD to add to the document - @param encodingType the character encoding format string to put into the xml - header - @param lineWrapLength the line length that will be used before items get placed on - a new line. This isn't an absolute maximum length, it just - determines how lists of attributes get broken up - @returns true if the file is written successfully; false if something goes wrong - in the process - @see createDocument - */ - bool writeToFile (const File& destinationFile, - const String& dtdToUse, - const tchar* const encodingType = JUCE_T("UTF-8"), - const int lineWrapLength = 60) const throw(); + if ((numUsed << 1) < data.numAllocated) + minimiseStorageOverheads(); + } - /** Returns this element's tag type name. + lock.exit(); + } - E.g. for an element such as \, this would return - "MOOSE". + /** Removes the first occurrence of a specified object from the array. - @see hasTagName + If the item isn't found, no action is taken. If it is found, it is + removed and has its reference count decreased. + + @param objectToRemove the object to try to remove + @see remove, removeRange */ - inline const String& getTagName() const throw() { return tagName; } + void removeObject (ObjectClass* const objectToRemove) + { + lock.enter(); + remove (indexOf (objectToRemove)); + lock.exit(); + } - /** Tests whether this element has a particular tag name. + /** Removes a range of objects from the array. - @param possibleTagName the tag name you're comparing it with + This will remove a set of objects, starting from the given index, + and move any subsequent elements down to close the gap. - @see getTagName - */ - bool hasTagName (const tchar* const possibleTagName) const throw(); + If the range extends beyond the bounds of the array, it will + be safely clipped to the size of the array. - /** Returns the number of XML attributes this element contains. + The objects that are removed will have their reference counts decreased, + and may be deleted if not referenced from elsewhere. - E.g. for an element such as \, this would - return 2. + @param startIndex the index of the first object to remove + @param numberToRemove how many objects should be removed + @see remove, removeObject */ - int getNumAttributes() const throw(); - - /** Returns the name of one of the elements attributes. + void removeRange (const int startIndex, + const int numberToRemove) + { + lock.enter(); - E.g. for an element such as \, then - getAttributeName(1) would return "antlers". + const int start = jlimit (0, numUsed, startIndex); + const int end = jlimit (0, numUsed, startIndex + numberToRemove); - @see getAttributeValue, getStringAttribute - */ - const String& getAttributeName (const int attributeIndex) const throw(); + if (end > start) + { + int i; + for (i = start; i < end; ++i) + { + if (data.elements[i] != 0) + { + data.elements[i]->decReferenceCount(); + data.elements[i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) + } + } - /** Returns the value of one of the elements attributes. + const int rangeSize = end - start; + ObjectClass** e = data.elements + start; + i = numUsed - end; + numUsed -= rangeSize; - E.g. for an element such as \, then - getAttributeName(1) would return "2". + while (--i >= 0) + { + *e = e [rangeSize]; + ++e; + } - @see getAttributeName, getStringAttribute - */ - const String& getAttributeValue (const int attributeIndex) const throw(); + if ((numUsed << 1) < data.numAllocated) + minimiseStorageOverheads(); + } - // Attribute-handling methods.. + lock.exit(); + } - /** Checks whether the element contains an attribute with a certain name. */ - bool hasAttribute (const tchar* const attributeName) const throw(); + /** Removes the last n objects from the array. - /** Returns the value of a named attribute. + The objects that are removed will have their reference counts decreased, + and may be deleted if not referenced from elsewhere. - @param attributeName the name of the attribute to look up - @param defaultReturnValue a value to return if the element doesn't have an attribute - with this name + @param howManyToRemove how many objects to remove from the end of the array + @see remove, removeObject, removeRange */ - const String getStringAttribute (const tchar* const attributeName, - const tchar* const defaultReturnValue = 0) const throw(); + void removeLast (int howManyToRemove = 1) + { + lock.enter(); - /** Compares the value of a named attribute with a value passed-in. + if (howManyToRemove > numUsed) + howManyToRemove = numUsed; - @param attributeName the name of the attribute to look up - @param stringToCompareAgainst the value to compare it with - @param ignoreCase whether the comparison should be case-insensitive - @returns true if the value of the attribute is the same as the string passed-in; - false if it's different (or if no such attribute exists) - */ - bool compareAttribute (const tchar* const attributeName, - const tchar* const stringToCompareAgainst, - const bool ignoreCase = false) const throw(); + while (--howManyToRemove >= 0) + remove (numUsed - 1); - /** Returns the value of a named attribute as an integer. + lock.exit(); + } - This will try to find the attribute and convert it to an integer (using - the String::getIntValue() method). + /** Swaps a pair of objects in the array. - @param attributeName the name of the attribute to look up - @param defaultReturnValue a value to return if the element doesn't have an attribute - with this name - @see setAttribute (const tchar* const, int) + If either of the indexes passed in is out-of-range, nothing will happen, + otherwise the two objects at these positions will be exchanged. */ - int getIntAttribute (const tchar* const attributeName, - const int defaultReturnValue = 0) const throw(); + void swap (const int index1, + const int index2) throw() + { + lock.enter(); - /** Returns the value of a named attribute as floating-point. + if (((unsigned int) index1) < (unsigned int) numUsed + && ((unsigned int) index2) < (unsigned int) numUsed) + { + swapVariables (data.elements [index1], + data.elements [index2]); + } - This will try to find the attribute and convert it to an integer (using - the String::getDoubleValue() method). + lock.exit(); + } - @param attributeName the name of the attribute to look up - @param defaultReturnValue a value to return if the element doesn't have an attribute - with this name - @see setAttribute (const tchar* const, double) - */ - double getDoubleAttribute (const tchar* const attributeName, - const double defaultReturnValue = 0.0) const throw(); + /** Moves one of the objects to a different position. - /** Returns the value of a named attribute as a boolean. + This will move the object to a specified index, shuffling along + any intervening elements as required. - This will try to find the attribute and interpret it as a boolean. To do this, - it'll return true if the value is "1", "true", "y", etc, or false for other - values. + So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling + move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. - @param attributeName the name of the attribute to look up - @param defaultReturnValue a value to return if the element doesn't have an attribute - with this name + @param currentIndex the index of the object to be moved. If this isn't a + valid index, then nothing will be done + @param newIndex the index at which you'd like this object to end up. If this + is less than zero, it will be moved to the end of the array */ - bool getBoolAttribute (const tchar* const attributeName, - const bool defaultReturnValue = false) const throw(); + void move (const int currentIndex, + int newIndex) throw() + { + if (currentIndex != newIndex) + { + lock.enter(); - /** Adds a named attribute to the element. + if (((unsigned int) currentIndex) < (unsigned int) numUsed) + { + if (((unsigned int) newIndex) >= (unsigned int) numUsed) + newIndex = numUsed - 1; - If the element already contains an attribute with this name, it's value will - be updated to the new value. If there's no such attribute yet, a new one will - be added. + ObjectClass* const value = data.elements [currentIndex]; - Note that there are other setAttribute() methods that take integers, - doubles, etc. to make it easy to store numbers. + if (newIndex > currentIndex) + { + memmove (data.elements + currentIndex, + data.elements + currentIndex + 1, + (newIndex - currentIndex) * sizeof (ObjectClass*)); + } + else + { + memmove (data.elements + newIndex + 1, + data.elements + newIndex, + (currentIndex - newIndex) * sizeof (ObjectClass*)); + } - @param attributeName the name of the attribute to set - @param newValue the value to set it to - @see removeAttribute - */ - void setAttribute (const tchar* const attributeName, - const String& newValue) throw(); + data.elements [newIndex] = value; + } - /** Adds a named attribute to the element. + lock.exit(); + } + } - If the element already contains an attribute with this name, it's value will - be updated to the new value. If there's no such attribute yet, a new one will - be added. + /** Compares this array to another one. - Note that there are other setAttribute() methods that take integers, - doubles, etc. to make it easy to store numbers. - - @param attributeName the name of the attribute to set - @param newValue the value to set it to + @returns true only if the other array contains the same objects in the same order */ - void setAttribute (const tchar* const attributeName, - const tchar* const newValue) throw(); - - /** Adds a named attribute to the element, setting it to an integer value. - - If the element already contains an attribute with this name, it's value will - be updated to the new value. If there's no such attribute yet, a new one will - be added. + bool operator== (const ReferenceCountedArray& other) const throw() + { + other.lockArray(); + lock.enter(); - Note that there are other setAttribute() methods that take integers, - doubles, etc. to make it easy to store numbers. + bool result = numUsed == other.numUsed; - @param attributeName the name of the attribute to set - @param newValue the value to set it to - */ - void setAttribute (const tchar* const attributeName, - const int newValue) throw(); + if (result) + { + for (int i = numUsed; --i >= 0;) + { + if (data.elements [i] != other.data.elements [i]) + { + result = false; + break; + } + } + } - /** Adds a named attribute to the element, setting it to a floating-point value. + lock.exit(); + other.unlockArray(); - If the element already contains an attribute with this name, it's value will - be updated to the new value. If there's no such attribute yet, a new one will - be added. + return result; + } - Note that there are other setAttribute() methods that take integers, - doubles, etc. to make it easy to store numbers. + /** Compares this array to another one. - @param attributeName the name of the attribute to set - @param newValue the value to set it to + @see operator== */ - void setAttribute (const tchar* const attributeName, - const double newValue) throw(); - - /** Removes a named attribute from the element. + bool operator!= (const ReferenceCountedArray& other) const throw() + { + return ! operator== (other); + } - @param attributeName the name of the attribute to remove - @see removeAllAttributes - */ - void removeAttribute (const tchar* const attributeName) throw(); + /** Sorts the elements in the array. - /** Removes all attributes from this element. - */ - void removeAllAttributes() throw(); + This will use a comparator object to sort the elements into order. The object + passed must have a method of the form: + @code + int compareElements (ElementType first, ElementType second); + @endcode - // Child element methods.. + ..and this method must return: + - a value of < 0 if the first comes before the second + - a value of 0 if the two objects are equivalent + - a value of > 0 if the second comes before the first - /** Returns the first of this element's sub-elements. + To improve performance, the compareElements() method can be declared as static or const. - see getNextElement() for an example of how to iterate the sub-elements. + @param comparator the comparator to use for comparing elements. + @param retainOrderOfEquivalentItems if this is true, then items + which the comparator says are equivalent will be + kept in the order in which they currently appear + in the array. This is slower to perform, but may + be important in some cases. If it's false, a faster + algorithm is used, but equivalent elements may be + rearranged. - @see forEachXmlChildElement + @see sortArray */ - XmlElement* getFirstChildElement() const throw() { return firstChildElement; } + template + void sort (ElementComparator& comparator, + const bool retainOrderOfEquivalentItems = false) const throw() + { + (void) comparator; // if you pass in an object with a static compareElements() method, this + // avoids getting warning messages about the parameter being unused - /** Returns the next of this element's siblings. + lock.enter(); + sortArray (comparator, data.elements, 0, size() - 1, retainOrderOfEquivalentItems); + lock.exit(); + } - This can be used for iterating an element's sub-elements, e.g. - @code - XmlElement* child = myXmlDocument->getFirstChildElement(); + /** Reduces the amount of storage being used by the array. - while (child != 0) + Arrays typically allocate slightly more storage than they need, and after + removing elements, they may have quite a lot of unused space allocated. + This method will reduce the amount of allocated storage to a minimum. + */ + void minimiseStorageOverheads() throw() + { + lock.enter(); + + if (numUsed == 0) { - ...do stuff with this child.. + data.setAllocatedSize (0); + } + else + { + const int newAllocation = data.granularity * (numUsed / data.granularity + 1); - child = child->getNextElement(); + if (newAllocation < data.numAllocated) + data.setAllocatedSize (newAllocation); } - @endcode - Note that when iterating the child elements, some of them might be - text elements as well as XML tags - use isTextElement() to work this - out. + lock.exit(); + } - Also, it's much easier and neater to use this method indirectly via the - forEachXmlChildElement macro. + /** Locks the array's CriticalSection. - @returns the sibling element that follows this one, or zero if this is the last - element in its parent + Of course if the type of section used is a DummyCriticalSection, this won't + have any effect. - @see getNextElement, isTextElement, forEachXmlChildElement + @see unlockArray */ - inline XmlElement* getNextElement() const throw() { return nextElement; } - - /** Returns the next of this element's siblings which has the specified tag - name. - - This is like getNextElement(), but will scan through the list until it - finds an element with the given tag name. + void lockArray() const throw() + { + lock.enter(); + } - @see getNextElement, forEachXmlChildElementWithTagName - */ - XmlElement* getNextElementWithTagName (const tchar* const requiredTagName) const; + /** Unlocks the array's CriticalSection. - /** Returns the number of sub-elements in this element. + Of course if the type of section used is a DummyCriticalSection, this won't + have any effect. - @see getChildElement + @see lockArray */ - int getNumChildElements() const throw(); + void unlockArray() const throw() + { + lock.exit(); + } - /** Returns the sub-element at a certain index. + juce_UseDebuggingNewOperator - It's not very efficient to iterate the sub-elements by index - see - getNextElement() for an example of how best to iterate. +private: + ArrayAllocationBase data; + int numUsed; + TypeOfCriticalSectionToUse lock; +}; - @returns the n'th child of this element, or 0 if the index is out-of-range - @see getNextElement, isTextElement, getChildByName - */ - XmlElement* getChildElement (const int index) const throw(); +#endif // __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ +/********* End of inlined file: juce_ReferenceCountedArray.h *********/ - /** Returns the first sub-element with a given tag-name. +#endif +#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ - @param tagNameToLookFor the tag name of the element you want to find - @returns the first element with this tag name, or 0 if none is found - @see getNextElement, isTextElement, getChildElement - */ - XmlElement* getChildByName (const tchar* const tagNameToLookFor) const throw(); +#endif +#ifndef __JUCE_SORTEDSET_JUCEHEADER__ - /** Appends an element to this element's list of children. +/********* Start of inlined file: juce_SortedSet.h *********/ +#ifndef __JUCE_SORTEDSET_JUCEHEADER__ +#define __JUCE_SORTEDSET_JUCEHEADER__ - Child elements are deleted automatically when their parent is deleted, so - make sure the object that you pass in will not be deleted by anything else, - and make sure it's not already the child of another element. +#if JUCE_MSVC + #pragma warning (push) + #pragma warning (disable: 4512) +#endif - @see getFirstChildElement, getNextElement, getNumChildElements, - getChildElement, removeChildElement - */ - void addChildElement (XmlElement* const newChildElement) throw(); +/** + Holds a set of unique primitive objects, such as ints or doubles. - /** Inserts an element into this element's list of children. + A set can only hold one item with a given value, so if for example it's a + set of integers, attempting to add the same integer twice will do nothing + the second time. - Child elements are deleted automatically when their parent is deleted, so - make sure the object that you pass in will not be deleted by anything else, - and make sure it's not already the child of another element. + Internally, the list of items is kept sorted (which means that whatever + kind of primitive type is used must support the ==, <, >, <= and >= operators + to determine the order), and searching the set for known values is very fast + because it uses a binary-chop method. - @param newChildNode the element to add - @param indexToInsertAt the index at which to insert the new element - if this is - below zero, it will be added to the end of the list - @see addChildElement, insertChildElement - */ - void insertChildElement (XmlElement* const newChildNode, - int indexToInsertAt) throw(); + Note that if you're using a class or struct as the element type, it must be + capable of being copied or moved with a straightforward memcpy, rather than + needing construction and destruction code. - /** Replaces one of this element's children with another node. + To make all the set's methods thread-safe, pass in "CriticalSection" as the templated + TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. - If the current element passed-in isn't actually a child of this element, - this will return false and the new one won't be added. Otherwise, the - existing element will be deleted, replaced with the new one, and it - will return true. - */ - bool replaceChildElement (XmlElement* const currentChildElement, - XmlElement* const newChildNode) throw(); + @see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection +*/ +template +class SortedSet +{ +public: - /** Removes a child element. + /** Creates an empty set. - @param childToRemove the child to look for and remove - @param shouldDeleteTheChild if true, the child will be deleted, if false it'll - just remove it + @param granularity this is the size of increment by which the internal storage + used by the array will grow. Only change it from the default if you know the + array is going to be very big and needs to be able to grow efficiently. */ - void removeChildElement (XmlElement* const childToRemove, - const bool shouldDeleteTheChild) throw(); - - /** Deletes all the child elements in the element. + SortedSet (const int granularity = juceDefaultArrayGranularity) throw() + : data (granularity), + numUsed (0) + { + } - @see removeChildElement, deleteAllChildElementsWithTagName + /** Creates a copy of another set. + @param other the set to copy */ - void deleteAllChildElements() throw(); + SortedSet (const SortedSet& other) throw() + : data (other.data.granularity) + { + other.lockSet(); + numUsed = other.numUsed; + data.setAllocatedSize (other.numUsed); + memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); + other.unlockSet(); + } - /** Deletes all the child elements with a given tag name. + /** Destructor. */ + ~SortedSet() throw() + { + } - @see removeChildElement + /** Copies another set over this one. + @param other the set to copy */ - void deleteAllChildElementsWithTagName (const tchar* const tagName) throw(); - - /** Returns true if the given element is a child of this one. */ - bool containsChildElement (const XmlElement* const possibleChild) const throw(); + const SortedSet & operator= (const SortedSet & other) throw() + { + if (this != &other) + { + other.lockSet(); + lock.enter(); - /** Recursively searches all sub-elements to find one that contains the specified - child element. - */ - XmlElement* findParentElementOf (const XmlElement* const elementToLookFor) throw(); + data.granularity = other.data.granularity; + data.ensureAllocatedSize (other.size()); + numUsed = other.numUsed; + memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); + minimiseStorageOverheads(); - /** Sorts the child elements using a comparator. + lock.exit(); + other.unlockSet(); + } - This will use a comparator object to sort the elements into order. The object - passed must have a method of the form: - @code - int compareElements (const XmlElement* first, const XmlElement* second); - @endcode + return *this; + } - ..and this method must return: - - a value of < 0 if the first comes before the second - - a value of 0 if the two objects are equivalent - - a value of > 0 if the second comes before the first + /** Compares this set to another one. - To improve performance, the compareElements() method can be declared as static or const. + Two sets are considered equal if they both contain the same set of + elements. - @param comparator the comparator to use for comparing elements. - @param retainOrderOfEquivalentItems if this is true, then items - which the comparator says are equivalent will be - kept in the order in which they currently appear - in the array. This is slower to perform, but may - be important in some cases. If it's false, a faster - algorithm is used, but equivalent elements may be - rearranged. + @param other the other set to compare with */ - template - void sortChildElements (ElementComparator& comparator, - const bool retainOrderOfEquivalentItems = false) throw() + bool operator== (const SortedSet& other) const throw() { - const int num = getNumChildElements(); + lock.enter(); - if (num > 1) + if (numUsed != other.numUsed) { - XmlElement** const elems = getChildElementsAsArray (num); - sortArray (comparator, elems, 0, num - 1, retainOrderOfEquivalentItems); - reorderChildElements (elems, num); - delete[] elems; + lock.exit(); + return false; + } + + for (int i = numUsed; --i >= 0;) + { + if (data.elements [i] != other.data.elements [i]) + { + lock.exit(); + return false; + } } + + lock.exit(); + return true; } - /** Returns true if this element is a section of text. + /** Compares this set to another one. - Elements can either be an XML tag element or a secton of text, so this - is used to find out what kind of element this one is. + Two sets are considered equal if they both contain the same set of + elements. - @see getAllText, addTextElement, deleteAllTextElements + @param other the other set to compare with */ - bool isTextElement() const throw(); + bool operator!= (const SortedSet& other) const throw() + { + return ! operator== (other); + } - /** Returns the text for a text element. + /** Removes all elements from the set. - Note that if you have an element like this: + This will remove all the elements, and free any storage that the set is + using. To clear it without freeing the storage, use the clearQuick() + method instead. - @codehello@endcode + @see clearQuick + */ + void clear() throw() + { + lock.enter(); + data.setAllocatedSize (0); + numUsed = 0; + lock.exit(); + } - then calling getText on the "xyz" element won't return "hello", because that is - actually stored in a special text sub-element inside the xyz element. To get the - "hello" string, you could either call getText on the (unnamed) sub-element, or - use getAllSubText() to do this automatically. + /** Removes all elements from the set without freeing the array's allocated storage. - @see isTextElement, getAllSubText, getChildElementAllSubText + @see clear */ - const String getText() const throw(); - - /** Sets the text in a text element. + void clearQuick() throw() + { + lock.enter(); + numUsed = 0; + lock.exit(); + } - Note that this is only a valid call if this element is a text element. If it's - not, then no action will be performed. + /** Returns the current number of elements in the set. */ - void setText (const String& newText) throw(); + inline int size() const throw() + { + return numUsed; + } - /** Returns all the text from this element's child nodes. + /** Returns one of the elements in the set. - This iterates all the child elements and when it finds text elements, - it concatenates their text into a big string which it returns. + If the index passed in is beyond the range of valid elements, this + will return zero. - E.g. @code hello there @endcode - if you called getAllSubText on the "xyz" element, it'd return "hello there". + If you're certain that the index will always be a valid element, you + can call getUnchecked() instead, which is faster. - @see isTextElement, getChildElementAllSubText, getText, addTextElement + @param index the index of the element being requested (0 is the first element in the set) + @see getUnchecked, getFirst, getLast */ - const String getAllSubText() const throw(); - - /** Returns all the sub-text of a named child element. - - If there is a child element with the given tag name, this will return - all of its sub-text (by calling getAllSubText() on it). If there is - no such child element, this will return the default string passed-in. + inline ElementType operator[] (const int index) const throw() + { + lock.enter(); + const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) + ? data.elements [index] + : (ElementType) 0; + lock.exit(); - @see getAllSubText - */ - const String getChildElementAllSubText (const tchar* const childTagName, - const String& defaultReturnValue) const throw(); + return result; + } - /** Appends a section of text to this element. + /** Returns one of the elements in the set, without checking the index passed in. + Unlike the operator[] method, this will try to return an element without + checking that the index is within the bounds of the set, so should only + be used when you're confident that it will always be a valid index. - @see isTextElement, getText, getAllSubText + @param index the index of the element being requested (0 is the first element in the set) + @see operator[], getFirst, getLast */ - void addTextElement (const String& text) throw(); + inline ElementType getUnchecked (const int index) const throw() + { + lock.enter(); + jassert (((unsigned int) index) < (unsigned int) numUsed); + const ElementType result = data.elements [index]; + lock.exit(); - /** Removes all the text elements from this element. + return result; + } - @see isTextElement, getText, getAllSubText, addTextElement - */ - void deleteAllTextElements() throw(); + /** Returns the first element in the set, or 0 if the set is empty. - /** Creates a text element that can be added to a parent element. + @see operator[], getUnchecked, getLast */ - static XmlElement* createTextElement (const String& text) throw(); - - juce_UseDebuggingNewOperator + inline ElementType getFirst() const throw() + { + lock.enter(); + const ElementType result = (numUsed > 0) ? data.elements [0] + : (ElementType) 0; + lock.exit(); -private: - friend class XmlDocument; + return result; + } - String tagName; - XmlElement* firstChildElement; - XmlElement* nextElement; + /** Returns the last element in the set, or 0 if the set is empty. - struct XmlAttributeNode + @see operator[], getUnchecked, getFirst + */ + inline ElementType getLast() const throw() { - XmlAttributeNode (const XmlAttributeNode& other) throw(); - XmlAttributeNode (const String& name, const String& value) throw(); + lock.enter(); + const ElementType result = (numUsed > 0) ? data.elements [numUsed - 1] + : (ElementType) 0; + lock.exit(); - String name, value; - XmlAttributeNode* next; + return result; + } - private: - const XmlAttributeNode& operator= (const XmlAttributeNode&); - }; + /** Finds the index of the first element which matches the value passed in. - XmlAttributeNode* attributes; + This will search the set for the given object, and return the index + of its first occurrence. If the object isn't found, the method will return -1. - XmlElement (int) throw(); // for internal use - XmlElement (const tchar* const tagNameText, const int nameLen) throw(); + @param elementToLookFor the value or object to look for + @returns the index of the object, or -1 if it's not found + */ + int indexOf (const ElementType elementToLookFor) const throw() + { + lock.enter(); - void copyChildrenAndAttributesFrom (const XmlElement& other) throw(); + int start = 0; + int end = numUsed; - void writeElementAsText (OutputStream& out, - const int indentationLevel, - const int lineWrapLength) const throw(); - - XmlElement** getChildElementsAsArray (const int) const throw(); - void reorderChildElements (XmlElement** const, const int) throw(); -}; + for (;;) + { + if (start >= end) + { + lock.exit(); + return -1; + } + else if (elementToLookFor == data.elements [start]) + { + lock.exit(); + return start; + } + else + { + const int halfway = (start + end) >> 1; -#endif // __JUCE_XMLELEMENT_JUCEHEADER__ -/********* End of inlined file: juce_XmlElement.h *********/ + if (halfway == start) + { + lock.exit(); + return -1; + } + else if (elementToLookFor >= data.elements [halfway]) + start = halfway; + else + end = halfway; + } + } + } -/** - A set of named property values, which can be strings, integers, floating point, etc. + /** Returns true if the set contains at least one occurrence of an object. - Effectively, this just wraps a StringPairArray in an interface that makes it easier - to load and save types other than strings. + @param elementToLookFor the value or object to look for + @returns true if the item is found + */ + bool contains (const ElementType elementToLookFor) const throw() + { + lock.enter(); - See the PropertiesFile class for a subclass of this, which automatically broadcasts change - messages and saves/loads the list from a file. -*/ -class JUCE_API PropertySet -{ -public: + int start = 0; + int end = numUsed; - /** Creates an empty PropertySet. + for (;;) + { + if (start >= end) + { + lock.exit(); + return false; + } + else if (elementToLookFor == data.elements [start]) + { + lock.exit(); + return true; + } + else + { + const int halfway = (start + end) >> 1; - @param ignoreCaseOfKeyNames if true, the names of properties are compared in a - case-insensitive way - */ - PropertySet (const bool ignoreCaseOfKeyNames = false) throw(); + if (halfway == start) + { + lock.exit(); + return false; + } + else if (elementToLookFor >= data.elements [halfway]) + start = halfway; + else + end = halfway; + } + } + } - /** Creates a copy of another PropertySet. - */ - PropertySet (const PropertySet& other) throw(); + /** Adds a new element to the set, (as long as it's not already in there). - /** Copies another PropertySet over this one. + @param newElement the new object to add to the set + @see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray */ - const PropertySet& operator= (const PropertySet& other) throw(); + void add (const ElementType newElement) throw() + { + lock.enter(); - /** Destructor. */ - virtual ~PropertySet(); + int start = 0; + int end = numUsed; - /** Returns one of the properties as a string. + for (;;) + { + if (start >= end) + { + jassert (start <= end); + insertInternal (start, newElement); + break; + } + else if (newElement == data.elements [start]) + { + break; + } + else + { + const int halfway = (start + end) >> 1; - If the value isn't found in this set, then this will look for it in a fallback - property set (if you've specified one with the setFallbackPropertySet() method), - and if it can't find one there, it'll return the default value passed-in. + if (halfway == start) + { + if (newElement >= data.elements [halfway]) + insertInternal (start + 1, newElement); + else + insertInternal (start, newElement); - @param keyName the name of the property to retrieve - @param defaultReturnValue a value to return if the named property doesn't actually exist - */ - const String getValue (const String& keyName, - const String& defaultReturnValue = String::empty) const throw(); + break; + } + else if (newElement >= data.elements [halfway]) + start = halfway; + else + end = halfway; + } + } - /** Returns one of the properties as an integer. + lock.exit(); + } - If the value isn't found in this set, then this will look for it in a fallback - property set (if you've specified one with the setFallbackPropertySet() method), - and if it can't find one there, it'll return the default value passed-in. + /** Adds elements from an array to this set. - @param keyName the name of the property to retrieve - @param defaultReturnValue a value to return if the named property doesn't actually exist + @param elementsToAdd the array of elements to add + @param numElementsToAdd how many elements are in this other array + @see add */ - int getIntValue (const String& keyName, - const int defaultReturnValue = 0) const throw(); + void addArray (const ElementType* elementsToAdd, + int numElementsToAdd) throw() + { + lock.enter(); - /** Returns one of the properties as an double. + while (--numElementsToAdd >= 0) + add (*elementsToAdd++); - If the value isn't found in this set, then this will look for it in a fallback - property set (if you've specified one with the setFallbackPropertySet() method), - and if it can't find one there, it'll return the default value passed-in. + lock.exit(); + } - @param keyName the name of the property to retrieve - @param defaultReturnValue a value to return if the named property doesn't actually exist - */ - double getDoubleValue (const String& keyName, - const double defaultReturnValue = 0.0) const throw(); + /** Adds elements from another set to this one. - /** Returns one of the properties as an boolean. + @param setToAddFrom the set from which to copy the elements + @param startIndex the first element of the other set to start copying from + @param numElementsToAdd how many elements to add from the other set. If this + value is negative or greater than the number of available elements, + all available elements will be copied. + @see add + */ + template + void addSet (const OtherSetType& setToAddFrom, + int startIndex = 0, + int numElementsToAdd = -1) throw() + { + setToAddFrom.lockSet(); + lock.enter(); + jassert (this != &setToAddFrom); - The result will be true if the string found for this key name can be parsed as a non-zero - integer. + if (this != &setToAddFrom) + { + if (startIndex < 0) + { + jassertfalse + startIndex = 0; + } - If the value isn't found in this set, then this will look for it in a fallback - property set (if you've specified one with the setFallbackPropertySet() method), - and if it can't find one there, it'll return the default value passed-in. + if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size()) + numElementsToAdd = setToAddFrom.size() - startIndex; - @param keyName the name of the property to retrieve - @param defaultReturnValue a value to return if the named property doesn't actually exist - */ - bool getBoolValue (const String& keyName, - const bool defaultReturnValue = false) const throw(); + addArray (setToAddFrom.elements + startIndex, numElementsToAdd); + } - /** Returns one of the properties as an XML element. + lock.exit(); + setToAddFrom.unlockSet(); + } - The result will a new XMLElement object that the caller must delete. If may return 0 if the - key isn't found, or if the entry contains an string that isn't valid XML. + /** Removes an element from the set. - If the value isn't found in this set, then this will look for it in a fallback - property set (if you've specified one with the setFallbackPropertySet() method), - and if it can't find one there, it'll return the default value passed-in. + This will remove the element at a given index. + If the index passed in is out-of-range, nothing will happen. - @param keyName the name of the property to retrieve + @param indexToRemove the index of the element to remove + @returns the element that has been removed + @see removeValue, removeRange */ - XmlElement* getXmlValue (const String& keyName) const; + ElementType remove (const int indexToRemove) throw() + { + lock.enter(); - /** Sets a named property as a string. + if (((unsigned int) indexToRemove) < (unsigned int) numUsed) + { + --numUsed; - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - */ - void setValue (const String& keyName, const String& value) throw(); + ElementType* const e = data.elements + indexToRemove; + ElementType const removed = *e; + const int numberToShift = numUsed - indexToRemove; - /** Sets a named property as a string. + if (numberToShift > 0) + memmove (e, e + 1, numberToShift * sizeof (ElementType)); - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - */ - void setValue (const String& keyName, const tchar* const value) throw(); + if ((numUsed << 1) < data.numAllocated) + minimiseStorageOverheads(); - /** Sets a named property to an integer. + lock.exit(); + return removed; + } + else + { + lock.exit(); + return 0; + } + } - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - */ - void setValue (const String& keyName, const int value) throw(); + /** Removes an item from the set. - /** Sets a named property to a double. + This will remove the given element from the set, if it's there. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to + @param valueToRemove the object to try to remove + @see remove, removeRange */ - void setValue (const String& keyName, const double value) throw(); + void removeValue (const ElementType valueToRemove) throw() + { + lock.enter(); + remove (indexOf (valueToRemove)); + lock.exit(); + } - /** Sets a named property to a boolean. + /** Removes any elements which are also in another set. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to + @param otherSet the other set in which to look for elements to remove + @see removeValuesNotIn, remove, removeValue, removeRange */ - void setValue (const String& keyName, const bool value) throw(); + template + void removeValuesIn (const OtherSetType& otherSet) throw() + { + otherSet.lockSet(); + lock.enter(); - /** Sets a named property to an XML element. + if (this == &otherSet) + { + clear(); + } + else + { + if (otherSet.size() > 0) + { + for (int i = numUsed; --i >= 0;) + if (otherSet.contains (data.elements [i])) + remove (i); + } + } - @param keyName the name of the property to set. (This mustn't be an empty string) - @param xml the new element to set it to. If this is zero, the value will be set to - an empty string - @see getXmlValue - */ - void setValue (const String& keyName, const XmlElement* const xml); + lock.exit(); + otherSet.unlockSet(); + } - /** Deletes a property. + /** Removes any elements which are not found in another set. - @param keyName the name of the property to delete. (This mustn't be an empty string) + Only elements which occur in this other set will be retained. + + @param otherSet the set in which to look for elements NOT to remove + @see removeValuesIn, remove, removeValue, removeRange */ - void removeValue (const String& keyName) throw(); + template + void removeValuesNotIn (const OtherSetType& otherSet) throw() + { + otherSet.lockSet(); + lock.enter(); - /** Returns true if the properies include the given key. */ - bool containsKey (const String& keyName) const throw(); + if (this != &otherSet) + { + if (otherSet.size() <= 0) + { + clear(); + } + else + { + for (int i = numUsed; --i >= 0;) + if (! otherSet.contains (data.elements [i])) + remove (i); + } + } - /** Removes all values. */ - void clear(); + lock.exit(); + otherSet.lockSet(); + } - /** Returns the keys/value pair array containing all the properties. */ - StringPairArray& getAllProperties() throw() { return properties; } + /** Reduces the amount of storage being used by the set. - /** Returns the lock used when reading or writing to this set */ - const CriticalSection& getLock() const throw() { return lock; } + Sets typically allocate slightly more storage than they need, and after + removing elements, they may have quite a lot of unused space allocated. + This method will reduce the amount of allocated storage to a minimum. + */ + void minimiseStorageOverheads() throw() + { + lock.enter(); - /** Returns an XML element which encapsulates all the items in this property set. + if (numUsed == 0) + { + data.setAllocatedSize (0); + } + else + { + const int newAllocation = data.granularity * (numUsed / data.granularity + 1); - The string parameter is the tag name that should be used for the node. + if (newAllocation < data.numAllocated) + data.setAllocatedSize (newAllocation); + } - @see restoreFromXml - */ - XmlElement* createXml (const String& nodeName) const throw(); + lock.exit(); + } - /** Reloads a set of properties that were previously stored as XML. + /** Locks the set's CriticalSection. - The node passed in must have been created by the createXml() method. + Of course if the type of section used is a DummyCriticalSection, this won't + have any effect. - @see createXml + @see unlockSet */ - void restoreFromXml (const XmlElement& xml) throw(); - - /** Sets up a second PopertySet that will be used to look up any values that aren't - set in this one. - - If you set this up to be a pointer to a second property set, then whenever one - of the getValue() methods fails to find an entry in this set, it will look up that - value in the fallback set, and if it finds it, it will return that. + void lockSet() const throw() + { + lock.enter(); + } - Make sure that you don't delete the fallback set while it's still being used by - another set! To remove the fallback set, just call this method with a null pointer. + /** Unlocks the set's CriticalSection. - @see getFallbackPropertySet - */ - void setFallbackPropertySet (PropertySet* fallbackProperties) throw(); + Of course if the type of section used is a DummyCriticalSection, this won't + have any effect. - /** Returns the fallback property set. - @see setFallbackPropertySet + @see lockSet */ - PropertySet* getFallbackPropertySet() const throw() { return fallbackProperties; } + void unlockSet() const throw() + { + lock.exit(); + } juce_UseDebuggingNewOperator -protected: +private: + ArrayAllocationBase data; + int numUsed; + TypeOfCriticalSectionToUse lock; - /** Subclasses can override this to be told when one of the properies has been changed. - */ - virtual void propertyChanged(); + void insertInternal (const int indexToInsertAt, const ElementType newElement) throw() + { + data.ensureAllocatedSize (numUsed + 1); -private: + ElementType* const insertPos = data.elements + indexToInsertAt; + const int numberToMove = numUsed - indexToInsertAt; - StringPairArray properties; - PropertySet* fallbackProperties; - CriticalSection lock; - bool ignoreCaseOfKeys; + if (numberToMove > 0) + memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); + + *insertPos = newElement; + ++numUsed; + } }; -#endif // __JUCE_PROPERTYSET_JUCEHEADER__ -/********* End of inlined file: juce_PropertySet.h *********/ +#if JUCE_MSVC + #pragma warning (pop) +#endif + +#endif // __JUCE_SORTEDSET_JUCEHEADER__ +/********* End of inlined file: juce_SortedSet.h *********/ #endif -#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ +#ifndef __JUCE_SPARSESET_JUCEHEADER__ -/********* Start of inlined file: juce_ReferenceCountedArray.h *********/ -#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ -#define __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ +/********* Start of inlined file: juce_SparseSet.h *********/ +#ifndef __JUCE_SPARSESET_JUCEHEADER__ +#define __JUCE_SPARSESET_JUCEHEADER__ /** - Holds a list of objects derived from ReferenceCountedObject. - - A ReferenceCountedArray holds objects derived from ReferenceCountedObject, - and takes care of incrementing and decrementing their ref counts when they - are added and removed from the array. + Holds a set of primitive values, storing them as a set of ranges. - To make all the array's methods thread-safe, pass in "CriticalSection" as the templated - TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. + This container acts like a simple BitArray, but can efficiently hold large + continguous ranges of values. It's quite a specialised class, mostly useful + for things like keeping the set of selected rows in a listbox. - @see Array, OwnedArray, StringArray + The type used as a template paramter must be an integer type, such as int, short, + int64, etc. */ -template -class ReferenceCountedArray +template +class SparseSet { public: - /** Creates an empty array. + /** Creates a new empty set. */ + SparseSet() throw() + { + } - @param granularity this is the size of increment by which the internal storage - used by the array will grow. Only change it from the default if you know the - array is going to be very big and needs to be able to grow efficiently. + /** Creates a copy of another SparseSet. */ + SparseSet (const SparseSet& other) throw() + : values (other.values) + { + } - @see ReferenceCountedObject, Array, OwnedArray - */ - ReferenceCountedArray (const int granularity = juceDefaultArrayGranularity) throw() - : data (granularity), - numUsed (0) + /** Destructor. */ + ~SparseSet() throw() { } - /** Creates a copy of another array */ - ReferenceCountedArray (const ReferenceCountedArray& other) throw() - : data (other.data.granularity) + /** Clears the set. */ + void clear() throw() { - other.lockArray(); - numUsed = other.numUsed; - data.setAllocatedSize (numUsed); - memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); + values.clear(); + } - for (int i = numUsed; --i >= 0;) - if (data.elements[i] != 0) - data.elements[i]->incReferenceCount(); + /** Checks whether the set is empty. - other.unlockArray(); + This is much quicker than using (size() == 0). + */ + bool isEmpty() const throw() + { + return values.size() == 0; } - /** Copies another array into this one. + /** Returns the number of values in the set. - Any existing objects in this array will first be released. + Because of the way the data is stored, this method can take longer if there + are a lot of items in the set. Use isEmpty() for a quick test of whether there + are any items. */ - const ReferenceCountedArray& operator= (const ReferenceCountedArray& other) throw() + Type size() const throw() { - if (this != &other) - { - other.lockArray(); - lock.enter(); - - clear(); - - data.granularity = other.granularity; - data.ensureAllocatedSize (other.numUsed); - numUsed = other.numUsed; - memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); - minimiseStorageOverheads(); - - for (int i = numUsed; --i >= 0;) - if (data.elements[i] != 0) - data.elements[i]->incReferenceCount(); - - lock.exit(); - other.unlockArray(); - } - - return *this; - } + Type num = 0; - /** Destructor. + for (int i = 0; i < values.size(); i += 2) + num += values[i + 1] - values[i]; - Any objects in the array will be released, and may be deleted if not referenced from elsewhere. - */ - ~ReferenceCountedArray() - { - clear(); + return num; } - /** Removes all objects from the array. + /** Returns one of the values in the set. - Any objects in the array that are not referenced from elsewhere will be deleted. + @param index the index of the value to retrieve, in the range 0 to (size() - 1). + @returns the value at this index, or 0 if it's out-of-range */ - void clear() + Type operator[] (int index) const throw() { - lock.enter(); + for (int i = 0; i < values.size(); i += 2) + { + const Type s = values.getUnchecked(i); + const Type e = values.getUnchecked(i + 1); - while (numUsed > 0) - if (data.elements [--numUsed] != 0) - data.elements [numUsed]->decReferenceCount(); + if (index < e - s) + return s + index; - jassert (numUsed == 0); - data.setAllocatedSize (0); + index -= e - s; + } - lock.exit(); + return (Type) 0; } - /** Returns the current number of objects in the array. */ - inline int size() const throw() + /** Checks whether a particular value is in the set. */ + bool contains (const Type valueToLookFor) const throw() { - return numUsed; - } - - /** Returns a pointer to the object at this index in the array. - - If the index is out-of-range, this will return a null pointer, (and - it could be null anyway, because it's ok for the array to hold null - pointers as well as objects). + bool on = false; - @see getUnchecked - */ - inline const ReferenceCountedObjectPtr operator[] (const int index) const throw() - { - lock.enter(); - const ReferenceCountedObjectPtr result ((((unsigned int) index) < (unsigned int) numUsed) - ? data.elements [index] - : (ObjectClass*) 0); - lock.exit(); - return result; - } + for (int i = 0; i < values.size(); ++i) + { + if (values.getUnchecked(i) > valueToLookFor) + return on; - /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. + on = ! on; + } - This is a faster and less safe version of operator[] which doesn't check the index passed in, so - it can be used when you're sure the index if always going to be legal. - */ - inline const ReferenceCountedObjectPtr getUnchecked (const int index) const throw() - { - lock.enter(); - jassert (((unsigned int) index) < (unsigned int) numUsed); - const ReferenceCountedObjectPtr result (data.elements [index]); - lock.exit(); - return result; + return false; } - /** Returns a pointer to the first object in the array. + /** Returns the number of contiguous blocks of values. - This will return a null pointer if the array's empty. - @see getLast + @see getRange */ - inline const ReferenceCountedObjectPtr getFirst() const throw() + int getNumRanges() const throw() { - lock.enter(); - const ReferenceCountedObjectPtr result ((numUsed > 0) ? data.elements [0] - : (ObjectClass*) 0); - lock.exit(); - - return result; + return values.size() >> 1; } - /** Returns a pointer to the last object in the array. - - This will return a null pointer if the array's empty. - @see getFirst - */ - inline const ReferenceCountedObjectPtr getLast() const throw() - { - lock.enter(); - const ReferenceCountedObjectPtr result ((numUsed > 0) ? data.elements [numUsed - 1] - : (ObjectClass*) 0); - lock.exit(); - - return result; - } + /** Returns one of the contiguous ranges of values stored. - /** Finds the index of the first occurrence of an object in the array. + @param rangeIndex the index of the range to look up, between 0 + and (getNumRanges() - 1) + @param startValue on return, the value at the start of the range + @param numValues on return, the number of values in the range - @param objectToLookFor the object to look for - @returns the index at which the object was found, or -1 if it's not found + @see getTotalRange */ - int indexOf (const ObjectClass* const objectToLookFor) const throw() + bool getRange (const int rangeIndex, + Type& startValue, + Type& numValues) const throw() { - int result = -1; - - lock.enter(); - ObjectClass** e = data.elements; - - for (int i = numUsed; --i >= 0;) + if (((unsigned int) rangeIndex) < (unsigned int) getNumRanges()) { - if (objectToLookFor == *e) - { - result = (int) (e - data.elements); - break; - } + startValue = values [rangeIndex << 1]; + numValues = values [(rangeIndex << 1) + 1] - startValue; - ++e; + return true; } - lock.exit(); - return result; + return false; } - /** Returns true if the array contains a specified object. + /** Returns the lowest and highest values in the set. - @param objectToLookFor the object to look for - @returns true if the object is in the array + @see getRange */ - bool contains (const ObjectClass* const objectToLookFor) const throw() + bool getTotalRange (Type& lowestValue, + Type& highestValue) const throw() { - lock.enter(); - ObjectClass** e = data.elements; - - for (int i = numUsed; --i >= 0;) + if (values.size() > 0) { - if (objectToLookFor == *e) - { - lock.exit(); - return true; - } - - ++e; + lowestValue = values.getUnchecked (0); + highestValue = values.getUnchecked (values.size() - 1); + return true; } - lock.exit(); return false; } - /** Appends a new object to the end of the array. + /** Adds a range of contiguous values to the set. - This will increase the new object's reference count. + e.g. addRange (10, 4) will add (10, 11, 12, 13) to the set. - @param newObject the new object to add to the array - @see set, insert, addIfNotAlreadyThere, addSorted, addArray + @param firstValue the start of the range of values to add + @param numValuesToAdd how many values to add */ - void add (ObjectClass* const newObject) throw() + void addRange (const Type firstValue, + const Type numValuesToAdd) throw() { - lock.enter(); - data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = newObject; + jassert (numValuesToAdd >= 0); - if (newObject != 0) - newObject->incReferenceCount(); + if (numValuesToAdd > 0) + { + removeRange (firstValue, numValuesToAdd); - lock.exit(); - } + IntegerElementComparator sorter; + values.addSorted (sorter, firstValue); + values.addSorted (sorter, firstValue + numValuesToAdd); - /** Inserts a new object into the array at the given index. + simplify(); + } + } - If the index is less than 0 or greater than the size of the array, the - element will be added to the end of the array. - Otherwise, it will be inserted into the array, moving all the later elements - along to make room. + /** Removes a range of values from the set. - This will increase the new object's reference count. + e.g. removeRange (10, 4) will remove (10, 11, 12, 13) from the set. - @param indexToInsertAt the index at which the new element should be inserted - @param newObject the new object to add to the array - @see add, addSorted, addIfNotAlreadyThere, set + @param firstValue the start of the range of values to remove + @param numValuesToRemove how many values to remove */ - void insert (int indexToInsertAt, - ObjectClass* const newObject) throw() + void removeRange (const Type firstValue, + const Type numValuesToRemove) throw() { - if (indexToInsertAt >= 0) + jassert (numValuesToRemove >= 0); + + if (numValuesToRemove >= 0 + && firstValue < values.getLast()) { - lock.enter(); + const bool onAtStart = contains (firstValue - 1); + const Type lastValue = firstValue + jmin (numValuesToRemove, values.getLast() - firstValue); + const bool onAtEnd = contains (lastValue); - if (indexToInsertAt > numUsed) - indexToInsertAt = numUsed; + for (int i = values.size(); --i >= 0;) + { + if (values.getUnchecked(i) <= lastValue) + { + while (values.getUnchecked(i) >= firstValue) + { + values.remove (i); - data.ensureAllocatedSize (numUsed + 1); + if (--i < 0) + break; + } - ObjectClass** const e = data.elements + indexToInsertAt; - const int numToMove = numUsed - indexToInsertAt; + break; + } + } - if (numToMove > 0) - memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); + IntegerElementComparator sorter; - *e = newObject; + if (onAtStart) + values.addSorted (sorter, firstValue); - if (newObject != 0) - newObject->incReferenceCount(); + if (onAtEnd) + values.addSorted (sorter, lastValue); - ++numUsed; - lock.exit(); - } - else - { - add (newObject); + simplify(); } } - /** Appends a new object at the end of the array as long as the array doesn't - already contain it. - - If the array already contains a matching object, nothing will be done. - - @param newObject the new object to add to the array - */ - void addIfNotAlreadyThere (ObjectClass* const newObject) throw() + /** Does an XOR of the values in a given range. */ + void invertRange (const Type firstValue, + const Type numValues) { - lock.enter(); + SparseSet newItems; + newItems.addRange (firstValue, numValues); - if (! contains (newObject)) - add (newObject); + int i; + for (i = getNumRanges(); --i >= 0;) + { + const int start = values [i << 1]; + const int end = values [(i << 1) + 1]; - lock.exit(); - } + newItems.removeRange (start, end); + } - /** Replaces an object in the array with a different one. + removeRange (firstValue, numValues); - If the index is less than zero, this method does nothing. - If the index is beyond the end of the array, the new object is added to the end of the array. + for (i = newItems.getNumRanges(); --i >= 0;) + { + const int start = newItems.values [i << 1]; + const int end = newItems.values [(i << 1) + 1]; - The object being added has its reference count increased, and if it's replacing - another object, then that one has its reference count decreased, and may be deleted. + addRange (start, end); + } + } - @param indexToChange the index whose value you want to change - @param newObject the new value to set for this index. - @see add, insert, remove - */ - void set (const int indexToChange, - ObjectClass* const newObject) + /** Checks whether any part of a given range overlaps any part of this one. */ + bool overlapsRange (const Type firstValue, + const Type numValues) throw() { - if (indexToChange >= 0) - { - lock.enter(); - - if (newObject != 0) - newObject->incReferenceCount(); + jassert (numValues >= 0); - if (indexToChange < numUsed) + if (numValues > 0) + { + for (int i = getNumRanges(); --i >= 0;) { - if (data.elements [indexToChange] != 0) - data.elements [indexToChange]->decReferenceCount(); + if (firstValue >= values.getUnchecked ((i << 1) + 1)) + return false; - data.elements [indexToChange] = newObject; - } - else - { - data.ensureAllocatedSize (numUsed + 1); - data.elements [numUsed++] = newObject; + if (firstValue + numValues > values.getUnchecked (i << 1)) + return true; } - - lock.exit(); } - } - /** Adds elements from another array to the end of this array. + return false; + } - @param arrayToAddFrom the array from which to copy the elements - @param startIndex the first element of the other array to start copying from - @param numElementsToAdd how many elements to add from the other array. If this - value is negative or greater than the number of available elements, - all available elements will be copied. - @see add - */ - void addArray (const ReferenceCountedArray& arrayToAddFrom, - int startIndex = 0, - int numElementsToAdd = -1) throw() + /** Checks whether the whole of a given range is contained within this one. */ + bool containsRange (const Type firstValue, + const Type numValues) throw() { - arrayToAddFrom.lockArray(); - lock.enter(); - - if (startIndex < 0) - { - jassertfalse - startIndex = 0; - } - - if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) - numElementsToAdd = arrayToAddFrom.size() - startIndex; + jassert (numValues >= 0); - if (numElementsToAdd > 0) + if (numValues > 0) { - data.ensureAllocatedSize (numUsed + numElementsToAdd); + for (int i = getNumRanges(); --i >= 0;) + { + if (firstValue >= values.getUnchecked ((i << 1) + 1)) + return false; - while (--numElementsToAdd >= 0) - add (arrayToAddFrom.getUnchecked (startIndex++)); + if (firstValue >= values.getUnchecked (i << 1) + && firstValue + numValues <= values.getUnchecked ((i << 1) + 1)) + return true; + } } - lock.exit(); - arrayToAddFrom.unlockArray(); + return false; } - /** Inserts a new object into the array assuming that the array is sorted. - - This will use a comparator to find the position at which the new object - should go. If the array isn't sorted, the behaviour of this - method will be unpredictable. - - @param comparator the comparator object to use to compare the elements - see the - sort() method for details about this object's form - @param newObject the new object to insert to the array - @see add, sort - */ - template - void addSorted (ElementComparator& comparator, - ObjectClass* newObject) throw() + bool operator== (const SparseSet& other) throw() { - lock.enter(); - insert (findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed), newObject); - lock.exit(); + return values == other.values; } - /** Inserts or replaces an object in the array, assuming it is sorted. - - This is similar to addSorted, but if a matching element already exists, then it will be - replaced by the new one, rather than the new one being added as well. - */ - template - void addOrReplaceSorted (ElementComparator& comparator, - ObjectClass* newObject) throw() + bool operator!= (const SparseSet& other) throw() { - lock.enter(); - const int index = findInsertIndexInSortedArray (comparator, data.elements, newObject, 0, numUsed); - - if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0) - set (index - 1, newObject); // replace an existing object that matches - else - insert (index, newObject); // no match, so insert the new one - - lock.exit(); + return values != other.values; } - /** Removes an object from the array. - - This will remove the object at a given index and move back all the - subsequent objects to close the gap. - - If the index passed in is out-of-range, nothing will happen. + juce_UseDebuggingNewOperator - The object that is removed will have its reference count decreased, - and may be deleted if not referenced from elsewhere. +private: + // alternating start/end values of ranges of values that are present. + Array values; - @param indexToRemove the index of the element to remove - @see removeObject, removeRange - */ - void remove (const int indexToRemove) + void simplify() throw() { - lock.enter(); - - if (((unsigned int) indexToRemove) < (unsigned int) numUsed) - { - ObjectClass** const e = data.elements + indexToRemove; + jassert ((values.size() & 1) == 0); - if (*e != 0) - (*e)->decReferenceCount(); + for (int i = values.size(); --i > 0;) + if (values.getUnchecked(i) == values.getUnchecked (i - 1)) + values.removeRange (i - 1, 2); + } +}; - --numUsed; - const int numberToShift = numUsed - indexToRemove; +#endif // __JUCE_SPARSESET_JUCEHEADER__ +/********* End of inlined file: juce_SparseSet.h *********/ - if (numberToShift > 0) - memmove (e, e + 1, numberToShift * sizeof (ObjectClass*)); +#endif +#ifndef __JUCE_VALUETREE_JUCEHEADER__ - if ((numUsed << 1) < data.numAllocated) - minimiseStorageOverheads(); - } +/********* Start of inlined file: juce_ValueTree.h *********/ +#ifndef __JUCE_VALUETREE_JUCEHEADER__ +#define __JUCE_VALUETREE_JUCEHEADER__ - lock.exit(); - } +/********* Start of inlined file: juce_Variant.h *********/ +#ifndef __JUCE_VARIANT_JUCEHEADER__ +#define __JUCE_VARIANT_JUCEHEADER__ - /** Removes the first occurrence of a specified object from the array. +class JUCE_API DynamicObject; - If the item isn't found, no action is taken. If it is found, it is - removed and has its reference count decreased. +/** + A variant class, that can be used to hold a range of primitive values. - @param objectToRemove the object to try to remove - @see remove, removeRange - */ - void removeObject (ObjectClass* const objectToRemove) - { - lock.enter(); - remove (indexOf (objectToRemove)); - lock.exit(); - } + A var object can hold a range of simple primitive values, strings, or + a reference-counted pointer to a DynamicObject. The var class is intended + to act like the values used in dynamic scripting languages. - /** Removes a range of objects from the array. + @see DynamicObject +*/ +class JUCE_API var +{ +public: - This will remove a set of objects, starting from the given index, - and move any subsequent elements down to close the gap. + typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments); - If the range extends beyond the bounds of the array, it will - be safely clipped to the size of the array. + /** Creates a void variant. */ + var() throw(); - The objects that are removed will have their reference counts decreased, - and may be deleted if not referenced from elsewhere. + /** Destructor. */ + ~var(); - @param startIndex the index of the first object to remove - @param numberToRemove how many objects should be removed - @see remove, removeObject - */ - void removeRange (const int startIndex, - const int numberToRemove) - { - lock.enter(); - - const int start = jlimit (0, numUsed, startIndex); - const int end = jlimit (0, numUsed, startIndex + numberToRemove); - - if (end > start) - { - int i; - for (i = start; i < end; ++i) - { - if (data.elements[i] != 0) - { - data.elements[i]->decReferenceCount(); - data.elements[i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) - } - } - - const int rangeSize = end - start; - ObjectClass** e = data.elements + start; - i = numUsed - end; - numUsed -= rangeSize; - - while (--i >= 0) - { - *e = e [rangeSize]; - ++e; - } + var (const var& valueToCopy) throw(); + var (const int value) throw(); + var (const bool value) throw(); + var (const double value) throw(); + var (const char* const value) throw(); + var (const juce_wchar* const value) throw(); + var (const String& value) throw(); + var (DynamicObject* const object) throw(); + var (MethodFunction method) throw(); - if ((numUsed << 1) < data.numAllocated) - minimiseStorageOverheads(); - } + const var& operator= (const var& valueToCopy) throw(); + const var& operator= (const int value) throw(); + const var& operator= (const bool value) throw(); + const var& operator= (const double value) throw(); + const var& operator= (const char* const value) throw(); + const var& operator= (const juce_wchar* const value) throw(); + const var& operator= (const String& value) throw(); + const var& operator= (DynamicObject* const object) throw(); + const var& operator= (MethodFunction method) throw(); - lock.exit(); - } + operator int() const throw(); + operator bool() const throw(); + operator float() const throw(); + operator double() const throw(); + operator const String() const throw(); + const String toString() const throw(); + DynamicObject* getObject() const throw(); - /** Removes the last n objects from the array. + bool isVoid() const throw() { return type == voidType; } + bool isInt() const throw() { return type == intType; } + bool isBool() const throw() { return type == boolType; } + bool isDouble() const throw() { return type == doubleType; } + bool isString() const throw() { return type == stringType; } + bool isObject() const throw() { return type == objectType; } + bool isMethod() const throw() { return type == methodType; } - The objects that are removed will have their reference counts decreased, - and may be deleted if not referenced from elsewhere. + bool operator== (const var& other) const throw(); + bool operator!= (const var& other) const throw(); - @param howManyToRemove how many objects to remove from the end of the array - @see remove, removeObject, removeRange + /** Writes a binary representation of this value to a stream. + The data can be read back later using readFromStream(). */ - void removeLast (int howManyToRemove = 1) - { - lock.enter(); - - if (howManyToRemove > numUsed) - howManyToRemove = numUsed; - - while (--howManyToRemove >= 0) - remove (numUsed - 1); - - lock.exit(); - } - - /** Swaps a pair of objects in the array. + void writeToStream (OutputStream& output) const throw(); - If either of the indexes passed in is out-of-range, nothing will happen, - otherwise the two objects at these positions will be exchanged. + /** Reads back a stored binary representation of a value. + The data in the stream must have been written using writeToStream(), or this + will have unpredictable results. */ - void swap (const int index1, - const int index2) throw() + static const var readFromStream (InputStream& input) throw(); + + class JUCE_API identifier { - lock.enter(); + public: + identifier (const char* const name) throw(); + identifier (const String& name) throw(); + ~identifier() throw(); - if (((unsigned int) index1) < (unsigned int) numUsed - && ((unsigned int) index2) < (unsigned int) numUsed) + bool operator== (const identifier& other) const throw() { - swapVariables (data.elements [index1], - data.elements [index2]); + jassert (hashCode != other.hashCode || name == other.name); // check for name hash collisions + return hashCode == other.hashCode; } - lock.exit(); - } + String name; + int hashCode; + }; - /** Moves one of the objects to a different position. + /** If this variant is an object, this returns one of its properties. */ + const var operator[] (const identifier& propertyName) const throw(); - This will move the object to a specified index, shuffling along - any intervening elements as required. + /** If this variant is an object, this invokes one of its methods with no arguments. */ + const var call (const identifier& method) const; + /** If this variant is an object, this invokes one of its methods with one argument. */ + const var call (const identifier& method, const var& arg1) const; + /** If this variant is an object, this invokes one of its methods with 2 arguments. */ + const var call (const identifier& method, const var& arg1, const var& arg2) const; + /** If this variant is an object, this invokes one of its methods with 3 arguments. */ + const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3); + /** If this variant is an object, this invokes one of its methods with 4 arguments. */ + const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; + /** If this variant is an object, this invokes one of its methods with 5 arguments. */ + const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; - So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling - move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. + /** If this variant is an object, this invokes one of its methods with a list of arguments. */ + const var invoke (const identifier& method, const var* arguments, int numArguments) const; - @param currentIndex the index of the object to be moved. If this isn't a - valid index, then nothing will be done - @param newIndex the index at which you'd like this object to end up. If this - is less than zero, it will be moved to the end of the array - */ - void move (const int currentIndex, - int newIndex) throw() - { - if (currentIndex != newIndex) - { - lock.enter(); + /** If this variant is a method pointer, this invokes it on a target object. */ + const var invoke (const var& targetObject, const var* arguments, int numArguments) const; - if (((unsigned int) currentIndex) < (unsigned int) numUsed) - { - if (((unsigned int) newIndex) >= (unsigned int) numUsed) - newIndex = numUsed - 1; + juce_UseDebuggingNewOperator - ObjectClass* const value = data.elements [currentIndex]; +private: + enum Type + { + voidType = 0, + intType, + boolType, + doubleType, + stringType, + objectType, + methodType + }; - if (newIndex > currentIndex) - { - memmove (data.elements + currentIndex, - data.elements + currentIndex + 1, - (newIndex - currentIndex) * sizeof (ObjectClass*)); - } - else - { - memmove (data.elements + newIndex + 1, - data.elements + newIndex, - (currentIndex - newIndex) * sizeof (ObjectClass*)); - } + Type type; - data.elements [newIndex] = value; - } + union + { + int intValue; + bool boolValue; + double doubleValue; + String* stringValue; + DynamicObject* objectValue; + MethodFunction methodValue; + } value; - lock.exit(); - } - } + void releaseValue() throw(); +}; - /** Compares this array to another one. +/** + Represents a dynamically implemented object. - @returns true only if the other array contains the same objects in the same order - */ - bool operator== (const ReferenceCountedArray& other) const throw() - { - other.lockArray(); - lock.enter(); + An instance of this class can be used to store named properties, and + by subclassing hasMethod() and invokeMethod(), you can give your object + methods. - bool result = numUsed == other.numUsed; + This is intended for use as a wrapper for scripting language objects. +*/ +class JUCE_API DynamicObject : public ReferenceCountedObject +{ +public: - if (result) - { - for (int i = numUsed; --i >= 0;) - { - if (data.elements [i] != other.data.elements [i]) - { - result = false; - break; - } - } - } + DynamicObject(); - lock.exit(); - other.unlockArray(); + /** Destructor. */ + virtual ~DynamicObject(); - return result; - } + /** Returns true if the object has a property with this name. + Note that if the property is actually a method, this will return false. + */ + virtual bool hasProperty (const var::identifier& propertyName) const; - /** Compares this array to another one. + /** Returns a named property. - @see operator== + This returns a void if no such property exists. */ - bool operator!= (const ReferenceCountedArray& other) const throw() - { - return ! operator== (other); - } + virtual const var getProperty (const var::identifier& propertyName) const; - /** Sorts the elements in the array. + /** Sets a named property. */ + virtual void setProperty (const var::identifier& propertyName, const var& newValue); - This will use a comparator object to sort the elements into order. The object - passed must have a method of the form: - @code - int compareElements (ElementType first, ElementType second); - @endcode + /** Removes a named property. */ + virtual void removeProperty (const var::identifier& propertyName); - ..and this method must return: - - a value of < 0 if the first comes before the second - - a value of 0 if the two objects are equivalent - - a value of > 0 if the second comes before the first + /** Checks whether this object has the specified method. - To improve performance, the compareElements() method can be declared as static or const. + The default implementation of this just checks whether there's a property + with this name that's actually a method, but this can be overridden for + building objects with dynamic invocation. + */ + virtual bool hasMethod (const var::identifier& methodName) const; - @param comparator the comparator to use for comparing elements. - @param retainOrderOfEquivalentItems if this is true, then items - which the comparator says are equivalent will be - kept in the order in which they currently appear - in the array. This is slower to perform, but may - be important in some cases. If it's false, a faster - algorithm is used, but equivalent elements may be - rearranged. + /** Invokes a named method on this object. - @see sortArray + The default implementation looks up the named property, and if it's a method + call, then it invokes it. + + This method is virtual to allow more dynamic invocation to used for objects + where the methods may not already be set as properies. */ - template - void sort (ElementComparator& comparator, - const bool retainOrderOfEquivalentItems = false) const throw() - { - (void) comparator; // if you pass in an object with a static compareElements() method, this - // avoids getting warning messages about the parameter being unused + virtual const var invokeMethod (const var::identifier& methodName, + const var* parameters, + int numParameters); - lock.enter(); - sortArray (comparator, data.elements, 0, size() - 1, retainOrderOfEquivalentItems); - lock.exit(); - } + /** Sets up a method. - /** Reduces the amount of storage being used by the array. + This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but + helps to avoid accidentally invoking the wrong type of var constructor. It also makes + the code easier to read, - Arrays typically allocate slightly more storage than they need, and after - removing elements, they may have quite a lot of unused space allocated. - This method will reduce the amount of allocated storage to a minimum. + The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g. + @code + setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething); + @endcode */ - void minimiseStorageOverheads() throw() - { - lock.enter(); - - if (numUsed == 0) - { - data.setAllocatedSize (0); - } - else - { - const int newAllocation = data.granularity * (numUsed / data.granularity + 1); + void setMethod (const var::identifier& methodName, + var::MethodFunction methodFunction); - if (newAllocation < data.numAllocated) - data.setAllocatedSize (newAllocation); - } + /** Removes all properties and methods from the object. */ + void clear(); - lock.exit(); - } + juce_UseDebuggingNewOperator - /** Locks the array's CriticalSection. +private: + Array propertyIds; + OwnedArray propertyValues; +}; - Of course if the type of section used is a DummyCriticalSection, this won't - have any effect. +#endif // __JUCE_VARIANT_JUCEHEADER__ +/********* End of inlined file: juce_Variant.h *********/ - @see unlockArray - */ - void lockArray() const throw() - { - lock.enter(); - } +/********* Start of inlined file: juce_UndoManager.h *********/ +#ifndef __JUCE_UNDOMANAGER_JUCEHEADER__ +#define __JUCE_UNDOMANAGER_JUCEHEADER__ - /** Unlocks the array's CriticalSection. +/********* Start of inlined file: juce_ChangeBroadcaster.h *********/ +#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ +#define __JUCE_CHANGEBROADCASTER_JUCEHEADER__ - Of course if the type of section used is a DummyCriticalSection, this won't - have any effect. +/********* Start of inlined file: juce_ChangeListenerList.h *********/ +#ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ +#define __JUCE_CHANGELISTENERLIST_JUCEHEADER__ - @see lockArray - */ - void unlockArray() const throw() - { - lock.exit(); - } +/********* Start of inlined file: juce_ChangeListener.h *********/ +#ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ +#define __JUCE_CHANGELISTENER_JUCEHEADER__ - juce_UseDebuggingNewOperator +/** + Receives callbacks about changes to some kind of object. -private: - ArrayAllocationBase data; - int numUsed; - TypeOfCriticalSectionToUse lock; -}; + 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. -#endif // __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ -/********* End of inlined file: juce_ReferenceCountedArray.h *********/ + 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. -#endif -#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ + @see ChangeListenerList, ChangeBroadcaster, ActionListener +*/ +class JUCE_API ChangeListener +{ +public: + /** Destructor. */ + virtual ~ChangeListener() {} -#endif -#ifndef __JUCE_SORTEDSET_JUCEHEADER__ + /** Overridden by your subclass to receive the callback. -/********* Start of inlined file: juce_SortedSet.h *********/ -#ifndef __JUCE_SORTEDSET_JUCEHEADER__ -#define __JUCE_SORTEDSET_JUCEHEADER__ + @param objectThatHasChanged the value that was passed to the + ChangeListenerList::sendChangeMessage() method + */ + virtual void changeListenerCallback (void* objectThatHasChanged) = 0; +}; -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4512) -#endif +#endif // __JUCE_CHANGELISTENER_JUCEHEADER__ +/********* End of inlined file: juce_ChangeListener.h *********/ -/** - Holds a set of unique primitive objects, such as ints or doubles. +/********* Start of inlined file: juce_MessageListener.h *********/ +#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ +#define __JUCE_MESSAGELISTENER_JUCEHEADER__ - A set can only hold one item with a given value, so if for example it's a - set of integers, attempting to add the same integer twice will do nothing - the second time. +/********* Start of inlined file: juce_Message.h *********/ +#ifndef __JUCE_MESSAGE_JUCEHEADER__ +#define __JUCE_MESSAGE_JUCEHEADER__ - Internally, the list of items is kept sorted (which means that whatever - kind of primitive type is used must support the ==, <, >, <= and >= operators - to determine the order), and searching the set for known values is very fast - because it uses a binary-chop method. +class MessageListener; +class MessageManager; - Note that if you're using a class or struct as the element type, it must be - capable of being copied or moved with a straightforward memcpy, rather than - needing construction and destruction code. +/** The base class for objects that can be delivered to a MessageListener. - To make all the set's methods thread-safe, pass in "CriticalSection" as the templated - TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. + The simplest Message object contains a few integer and pointer parameters + that the user can set, and this is enough for a lot of purposes. For passing more + complex data, subclasses of Message can also be used. - @see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection + @see MessageListener, MessageManager, ActionListener, ChangeListener */ -template -class SortedSet +class JUCE_API Message { public: - /** Creates an empty set. + /** Creates an uninitialised message. - @param granularity this is the size of increment by which the internal storage - used by the array will grow. Only change it from the default if you know the - array is going to be very big and needs to be able to grow efficiently. + The class's variables will also be left uninitialised. */ - SortedSet (const int granularity = juceDefaultArrayGranularity) throw() - : data (granularity), - numUsed (0) - { - } + Message() throw(); - /** Creates a copy of another set. - @param other the set to copy + /** Creates a message object, filling in the member variables. + + The corresponding public member variables will be set from the parameters + passed in. */ - SortedSet (const SortedSet& other) throw() - : data (other.data.granularity) - { - other.lockSet(); - numUsed = other.numUsed; - data.setAllocatedSize (other.numUsed); - memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); - other.unlockSet(); - } + Message (const int intParameter1, + const int intParameter2, + const int intParameter3, + void* const pointerParameter) throw(); /** Destructor. */ - ~SortedSet() throw() - { - } + virtual ~Message() throw(); - /** Copies another set over this one. - @param other the set to copy - */ - const SortedSet & operator= (const SortedSet & other) throw() - { - if (this != &other) - { - other.lockSet(); - lock.enter(); + // These values can be used for carrying simple data that the application needs to + // pass around. For more complex messages, just create a subclass. - data.granularity = other.data.granularity; - data.ensureAllocatedSize (other.size()); - numUsed = other.numUsed; - memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); - minimiseStorageOverheads(); + int intParameter1; /**< user-defined integer value. */ + int intParameter2; /**< user-defined integer value. */ + int intParameter3; /**< user-defined integer value. */ + void* pointerParameter; /**< user-defined pointer value. */ - lock.exit(); - other.unlockSet(); - } + juce_UseDebuggingNewOperator - return *this; - } +private: + friend class MessageListener; + friend class MessageManager; + MessageListener* messageRecipient; - /** Compares this set to another one. + Message (const Message&); + const Message& operator= (const Message&); +}; - Two sets are considered equal if they both contain the same set of - elements. - - @param other the other set to compare with - */ - bool operator== (const SortedSet& other) const throw() - { - lock.enter(); +#endif // __JUCE_MESSAGE_JUCEHEADER__ +/********* End of inlined file: juce_Message.h *********/ - if (numUsed != other.numUsed) - { - lock.exit(); - return false; - } +/** + MessageListener subclasses can post and receive Message objects. - for (int i = numUsed; --i >= 0;) - { - if (data.elements [i] != other.data.elements [i]) - { - lock.exit(); - return false; - } - } + @see Message, MessageManager, ActionListener, ChangeListener +*/ +class JUCE_API MessageListener +{ +protected: - lock.exit(); - return true; - } + /** Creates a MessageListener. */ + MessageListener() throw(); - /** Compares this set to another one. +public: - Two sets are considered equal if they both contain the same set of - elements. + /** Destructor. - @param other the other set to compare with + When a MessageListener is deleted, it removes itself from a global list + of registered listeners, so that the isValidMessageListener() method + will no longer return true. */ - bool operator!= (const SortedSet& other) const throw() - { - return ! operator== (other); - } + virtual ~MessageListener(); - /** Removes all elements from the set. + /** This is the callback method that receives incoming messages. - This will remove all the elements, and free any storage that the set is - using. To clear it without freeing the storage, use the clearQuick() - method instead. + This is called by the MessageManager from its dispatch loop. - @see clearQuick + @see postMessage */ - void clear() throw() - { - lock.enter(); - data.setAllocatedSize (0); - numUsed = 0; - lock.exit(); - } + virtual void handleMessage (const Message& message) = 0; - /** Removes all elements from the set without freeing the array's allocated storage. + /** Sends a message to the message queue, for asynchronous delivery to this listener + later on. - @see clear + This method can be called safely by any thread. + + @param message the message object to send - this will be deleted + automatically by the message queue, so don't keep any + references to it after calling this method. + @see handleMessage */ - void clearQuick() throw() - { - lock.enter(); - numUsed = 0; - lock.exit(); - } + void postMessage (Message* const message) const throw(); - /** Returns the current number of elements in the set. + /** Checks whether this MessageListener has been deleted. + + Although not foolproof, this method is safe to call on dangling or null + pointers. A list of active MessageListeners is kept internally, so this + checks whether the object is on this list or not. + + Note that it's possible to get a false-positive here, if an object is + deleted and another is subsequently created that happens to be at the + exact same memory location, but I can't think of a good way of avoiding + this. */ - inline int size() const throw() - { - return numUsed; - } + bool isValidMessageListener() const throw(); +}; - /** Returns one of the elements in the set. +#endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ +/********* End of inlined file: juce_MessageListener.h *********/ - If the index passed in is beyond the range of valid elements, this - will return zero. +/********* Start of inlined file: juce_ScopedLock.h *********/ +#ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ +#define __JUCE_SCOPEDLOCK_JUCEHEADER__ - If you're certain that the index will always be a valid element, you - can call getUnchecked() instead, which is faster. +/** + Automatically locks and unlocks a CriticalSection object. - @param index the index of the element being requested (0 is the first element in the set) - @see getUnchecked, getFirst, getLast - */ - inline ElementType operator[] (const int index) const throw() - { - lock.enter(); - const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) - ? data.elements [index] - : (ElementType) 0; - lock.exit(); + Use one of these as a local variable to control access to a CriticalSection. - return result; - } + e.g. @code - /** Returns one of the elements in the set, without checking the index passed in. - Unlike the operator[] method, this will try to return an element without - checking that the index is within the bounds of the set, so should only - be used when you're confident that it will always be a valid index. + CriticalSection myCriticalSection; - @param index the index of the element being requested (0 is the first element in the set) - @see operator[], getFirst, getLast - */ - inline ElementType getUnchecked (const int index) const throw() + for (;;) { - lock.enter(); - jassert (((unsigned int) index) < (unsigned int) numUsed); - const ElementType result = data.elements [index]; - lock.exit(); + const ScopedLock myScopedLock (myCriticalSection); + // myCriticalSection is now locked - return result; + ...do some stuff... + + // myCriticalSection gets unlocked here. } + @endcode - /** Returns the first element in the set, or 0 if the set is empty. + @see CriticalSection, ScopedUnlock +*/ +class JUCE_API ScopedLock +{ +public: - @see operator[], getUnchecked, getLast + /** Creates a ScopedLock. + + As soon as it is created, this will lock the CriticalSection, and + when the ScopedLock object is deleted, the CriticalSection will + be unlocked. + + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! Best just to use it + as a local stack object, rather than creating one with the new() operator. */ - inline ElementType getFirst() const throw() - { - lock.enter(); - const ElementType result = (numUsed > 0) ? data.elements [0] - : (ElementType) 0; - lock.exit(); + inline ScopedLock (const CriticalSection& lock) throw() : lock_ (lock) { lock.enter(); } - return result; - } + /** Destructor. - /** Returns the last element in the set, or 0 if the set is empty. + The CriticalSection will be unlocked when the destructor is called. - @see operator[], getUnchecked, getFirst + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! */ - inline ElementType getLast() const throw() - { - lock.enter(); - const ElementType result = (numUsed > 0) ? data.elements [numUsed - 1] - : (ElementType) 0; - lock.exit(); + inline ~ScopedLock() throw() { lock_.exit(); } - return result; - } +private: - /** Finds the index of the first element which matches the value passed in. + const CriticalSection& lock_; - This will search the set for the given object, and return the index - of its first occurrence. If the object isn't found, the method will return -1. + ScopedLock (const ScopedLock&); + const ScopedLock& operator= (const ScopedLock&); +}; - @param elementToLookFor the value or object to look for - @returns the index of the object, or -1 if it's not found - */ - int indexOf (const ElementType elementToLookFor) const throw() - { - lock.enter(); +/** + Automatically unlocks and re-locks a CriticalSection object. - int start = 0; - int end = numUsed; + This is the reverse of a ScopedLock object - instead of locking the critical + section for the lifetime of this object, it unlocks it. - for (;;) - { - if (start >= end) - { - lock.exit(); - return -1; - } - else if (elementToLookFor == data.elements [start]) - { - lock.exit(); - return start; - } - else - { - const int halfway = (start + end) >> 1; + Make sure you don't try to unlock critical sections that aren't actually locked! - if (halfway == start) - { - lock.exit(); - return -1; - } - else if (elementToLookFor >= data.elements [halfway]) - start = halfway; - else - end = halfway; - } - } - } + e.g. @code - /** Returns true if the set contains at least one occurrence of an object. + CriticalSection myCriticalSection; - @param elementToLookFor the value or object to look for - @returns true if the item is found - */ - bool contains (const ElementType elementToLookFor) const throw() + for (;;) { - lock.enter(); + const ScopedLock myScopedLock (myCriticalSection); + // myCriticalSection is now locked - int start = 0; - int end = numUsed; + ... do some stuff with it locked .. - for (;;) + while (xyz) { - if (start >= end) - { - lock.exit(); - return false; - } - else if (elementToLookFor == data.elements [start]) - { - lock.exit(); - return true; - } - else - { - const int halfway = (start + end) >> 1; + ... do some stuff with it locked .. - if (halfway == start) - { - lock.exit(); - return false; - } - else if (elementToLookFor >= data.elements [halfway]) - start = halfway; - else - end = halfway; - } - } - } + const ScopedUnlock unlocker (myCriticalSection); - /** Adds a new element to the set, (as long as it's not already in there). + // myCriticalSection is now unlocked for the remainder of this block, + // and re-locked at the end. - @param newElement the new object to add to the set - @see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray - */ - void add (const ElementType newElement) throw() - { - lock.enter(); + ...do some stuff with it unlocked ... + } - int start = 0; - int end = numUsed; + // myCriticalSection gets unlocked here. + } + @endcode - for (;;) - { - if (start >= end) - { - jassert (start <= end); - insertInternal (start, newElement); - break; - } - else if (newElement == data.elements [start]) - { - break; - } - else - { - const int halfway = (start + end) >> 1; + @see CriticalSection, ScopedLock +*/ +class ScopedUnlock +{ +public: - if (halfway == start) - { - if (newElement >= data.elements [halfway]) - insertInternal (start + 1, newElement); - else - insertInternal (start, newElement); + /** Creates a ScopedUnlock. - break; - } - else if (newElement >= data.elements [halfway]) - start = halfway; - else - end = halfway; - } - } + As soon as it is created, this will unlock the CriticalSection, and + when the ScopedLock object is deleted, the CriticalSection will + be re-locked. - lock.exit(); - } + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! Best just to use it + as a local stack object, rather than creating one with the new() operator. + */ + inline ScopedUnlock (const CriticalSection& lock) throw() : lock_ (lock) { lock.exit(); } - /** Adds elements from an array to this set. + /** Destructor. - @param elementsToAdd the array of elements to add - @param numElementsToAdd how many elements are in this other array - @see add + The CriticalSection will be unlocked when the destructor is called. + + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! */ - void addArray (const ElementType* elementsToAdd, - int numElementsToAdd) throw() - { - lock.enter(); + inline ~ScopedUnlock() throw() { lock_.enter(); } - while (--numElementsToAdd >= 0) - add (*elementsToAdd++); +private: - lock.exit(); - } + const CriticalSection& lock_; - /** Adds elements from another set to this one. + ScopedUnlock (const ScopedLock&); + const ScopedUnlock& operator= (const ScopedUnlock&); +}; - @param setToAddFrom the set from which to copy the elements - @param startIndex the first element of the other set to start copying from - @param numElementsToAdd how many elements to add from the other set. If this - value is negative or greater than the number of available elements, - all available elements will be copied. - @see add - */ - template - void addSet (const OtherSetType& setToAddFrom, - int startIndex = 0, - int numElementsToAdd = -1) throw() - { - setToAddFrom.lockSet(); - lock.enter(); - jassert (this != &setToAddFrom); +#endif // __JUCE_SCOPEDLOCK_JUCEHEADER__ +/********* End of inlined file: juce_ScopedLock.h *********/ - if (this != &setToAddFrom) - { - if (startIndex < 0) - { - jassertfalse - startIndex = 0; - } +/** + A set of ChangeListeners. - if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size()) - numElementsToAdd = setToAddFrom.size() - startIndex; + Listeners can be added and removed from the list, and change messages can be + broadcast to all the listeners. - addArray (setToAddFrom.elements + startIndex, numElementsToAdd); - } + @see ChangeListener, ChangeBroadcaster +*/ +class JUCE_API ChangeListenerList : public MessageListener +{ +public: - lock.exit(); - setToAddFrom.unlockSet(); - } + /** Creates an empty list. */ + ChangeListenerList() throw(); - /** Removes an element from the set. + /** Destructor. */ + ~ChangeListenerList() throw(); - This will remove the element at a given index. - If the index passed in is out-of-range, nothing will happen. + /** Adds a listener to the list. - @param indexToRemove the index of the element to remove - @returns the element that has been removed - @see removeValue, removeRange + (Trying to add a listener that's already on the list will have no effect). */ - ElementType remove (const int indexToRemove) throw() - { - lock.enter(); - - if (((unsigned int) indexToRemove) < (unsigned int) numUsed) - { - --numUsed; + void addChangeListener (ChangeListener* const listener) throw(); - ElementType* const e = data.elements + indexToRemove; - ElementType const removed = *e; - const int numberToShift = numUsed - indexToRemove; + /** Removes a listener from the list. - if (numberToShift > 0) - memmove (e, e + 1, numberToShift * sizeof (ElementType)); + If the listener isn't on the list, this won't have any effect. + */ + void removeChangeListener (ChangeListener* const listener) throw(); - if ((numUsed << 1) < data.numAllocated) - minimiseStorageOverheads(); + /** Removes all listeners from the list. */ + void removeAllChangeListeners() throw(); - lock.exit(); - return removed; - } - else - { - lock.exit(); - return 0; - } - } + /** Posts an asynchronous change message to all the listeners. - /** Removes an item from the set. + If a message has already been sent and hasn't yet been delivered, this + method won't send another - in this way it coalesces multiple frequent + changes into fewer actual callbacks to the ChangeListeners. Contrast this + with the ActionListener, which posts a new event for every call to its + sendActionMessage() method. - This will remove the given element from the set, if it's there. + Only listeners which are on the list when the change event is delivered + will receive the event - and this may include listeners that weren't on + the list when the change message was sent. - @param valueToRemove the object to try to remove - @see remove, removeRange + @param objectThatHasChanged this pointer is passed to the + ChangeListener::changeListenerCallback() method, + and can be any value the application needs + @see sendSynchronousChangeMessage */ - void removeValue (const ElementType valueToRemove) throw() - { - lock.enter(); - remove (indexOf (valueToRemove)); - lock.exit(); - } + void sendChangeMessage (void* objectThatHasChanged) throw(); - /** Removes any elements which are also in another set. + /** This will synchronously callback all the ChangeListeners. - @param otherSet the other set in which to look for elements to remove - @see removeValuesNotIn, remove, removeValue, removeRange + Use this if you need to synchronously force a call to all the + listeners' ChangeListener::changeListenerCallback() methods. */ - template - void removeValuesIn (const OtherSetType& otherSet) throw() - { - otherSet.lockSet(); - lock.enter(); + void sendSynchronousChangeMessage (void* objectThatHasChanged); - if (this == &otherSet) - { - clear(); - } - else - { - if (otherSet.size() > 0) - { - for (int i = numUsed; --i >= 0;) - if (otherSet.contains (data.elements [i])) - remove (i); - } - } + /** If a change message has been sent but not yet dispatched, this will + use sendSynchronousChangeMessage() to make the callback immediately. + */ + void dispatchPendingMessages(); - lock.exit(); - otherSet.unlockSet(); - } + /** @internal */ + void handleMessage (const Message&); - /** Removes any elements which are not found in another set. + juce_UseDebuggingNewOperator - Only elements which occur in this other set will be retained. +private: + SortedSet listeners; + CriticalSection lock; + void* lastChangedObject; + bool messagePending; - @param otherSet the set in which to look for elements NOT to remove - @see removeValuesIn, remove, removeValue, removeRange - */ - template - void removeValuesNotIn (const OtherSetType& otherSet) throw() - { - otherSet.lockSet(); - lock.enter(); + ChangeListenerList (const ChangeListenerList&); + const ChangeListenerList& operator= (const ChangeListenerList&); +}; - if (this != &otherSet) - { - if (otherSet.size() <= 0) - { - clear(); - } - else - { - for (int i = numUsed; --i >= 0;) - if (! otherSet.contains (data.elements [i])) - remove (i); - } - } +#endif // __JUCE_CHANGELISTENERLIST_JUCEHEADER__ +/********* End of inlined file: juce_ChangeListenerList.h *********/ - lock.exit(); - otherSet.lockSet(); - } +/** Manages a list of ChangeListeners, and can send them messages. - /** Reduces the amount of storage being used by the set. + To quickly add methods to your class that can add/remove change + listeners and broadcast to them, you can derive from this. - Sets typically allocate slightly more storage than they need, and after - removing elements, they may have quite a lot of unused space allocated. - This method will reduce the amount of allocated storage to a minimum. - */ - void minimiseStorageOverheads() throw() - { - lock.enter(); + @see ChangeListenerList, ChangeListener +*/ +class JUCE_API ChangeBroadcaster +{ +public: - if (numUsed == 0) - { - data.setAllocatedSize (0); - } - else - { - const int newAllocation = data.granularity * (numUsed / data.granularity + 1); + /** Creates an ChangeBroadcaster. */ + ChangeBroadcaster() throw(); - if (newAllocation < data.numAllocated) - data.setAllocatedSize (newAllocation); - } + /** Destructor. */ + virtual ~ChangeBroadcaster(); - lock.exit(); - } + /** Adds a listener to the list. - /** Locks the set's CriticalSection. + (Trying to add a listener that's already on the list will have no effect). + */ + void addChangeListener (ChangeListener* const listener) throw(); - Of course if the type of section used is a DummyCriticalSection, this won't - have any effect. + /** Removes a listener from the list. - @see unlockSet + If the listener isn't on the list, this won't have any effect. */ - void lockSet() const throw() - { - lock.enter(); - } + void removeChangeListener (ChangeListener* const listener) throw(); - /** Unlocks the set's CriticalSection. + /** Removes all listeners from the list. */ + void removeAllChangeListeners() throw(); - Of course if the type of section used is a DummyCriticalSection, this won't - have any effect. + /** Broadcasts a change message to all the registered listeners. - @see lockSet + The message will be delivered asynchronously by the event thread, so this + method will not directly call any of the listeners. For a synchronous + message, use sendSynchronousChangeMessage(). + + @see ChangeListenerList::sendActionMessage */ - void unlockSet() const throw() - { - lock.exit(); - } + void sendChangeMessage (void* objectThatHasChanged) throw(); - juce_UseDebuggingNewOperator + /** Sends a synchronous change message to all the registered listeners. -private: - ArrayAllocationBase data; - int numUsed; - TypeOfCriticalSectionToUse lock; + @see ChangeListenerList::sendSynchronousChangeMessage + */ + void sendSynchronousChangeMessage (void* objectThatHasChanged); - void insertInternal (const int indexToInsertAt, const ElementType newElement) throw() - { - data.ensureAllocatedSize (numUsed + 1); + /** If a change message has been sent but not yet dispatched, this will + use sendSynchronousChangeMessage() to make the callback immediately. + */ + void dispatchPendingMessages(); - ElementType* const insertPos = data.elements + indexToInsertAt; - const int numberToMove = numUsed - indexToInsertAt; +private: - if (numberToMove > 0) - memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); + ChangeListenerList changeListenerList; - *insertPos = newElement; - ++numUsed; - } + ChangeBroadcaster (const ChangeBroadcaster&); + const ChangeBroadcaster& operator= (const ChangeBroadcaster&); }; -#if JUCE_MSVC - #pragma warning (pop) -#endif - -#endif // __JUCE_SORTEDSET_JUCEHEADER__ -/********* End of inlined file: juce_SortedSet.h *********/ - -#endif -#ifndef __JUCE_SPARSESET_JUCEHEADER__ +#endif // __JUCE_CHANGEBROADCASTER_JUCEHEADER__ +/********* End of inlined file: juce_ChangeBroadcaster.h *********/ -/********* Start of inlined file: juce_SparseSet.h *********/ -#ifndef __JUCE_SPARSESET_JUCEHEADER__ -#define __JUCE_SPARSESET_JUCEHEADER__ +/********* Start of inlined file: juce_UndoableAction.h *********/ +#ifndef __JUCE_UNDOABLEACTION_JUCEHEADER__ +#define __JUCE_UNDOABLEACTION_JUCEHEADER__ /** - Holds a set of primitive values, storing them as a set of ranges. - - This container acts like a simple BitArray, but can efficiently hold large - continguous ranges of values. It's quite a specialised class, mostly useful - for things like keeping the set of selected rows in a listbox. + Used by the UndoManager class to store an action which can be done + and undone. - The type used as a template paramter must be an integer type, such as int, short, - int64, etc. + @see UndoManager */ -template -class SparseSet +class JUCE_API UndoableAction { +protected: + /** Creates an action. */ + UndoableAction() throw() {} + public: + /** Destructor. */ + virtual ~UndoableAction() {} - /** Creates a new empty set. */ - SparseSet() throw() - { - } + /** Overridden by a subclass to perform the action. - /** Creates a copy of another SparseSet. */ - SparseSet (const SparseSet& other) throw() - : values (other.values) - { - } + This method is called by the UndoManager, and shouldn't be used directly by + applications. - /** Destructor. */ - ~SparseSet() throw() - { - } + Be careful not to make any calls in a perform() method that could call + recursively back into the UndoManager::perform() method - /** Clears the set. */ - void clear() throw() - { - values.clear(); - } + @returns true if the action could be performed. + @see UndoManager::perform + */ + virtual bool perform() = 0; - /** Checks whether the set is empty. + /** Overridden by a subclass to undo the action. - This is much quicker than using (size() == 0). - */ - bool isEmpty() const throw() - { - return values.size() == 0; - } + This method is called by the UndoManager, and shouldn't be used directly by + applications. - /** Returns the number of values in the set. + Be careful not to make any calls in an undo() method that could call + recursively back into the UndoManager::perform() method - Because of the way the data is stored, this method can take longer if there - are a lot of items in the set. Use isEmpty() for a quick test of whether there - are any items. + @returns true if the action could be undone without any errors. + @see UndoManager::perform */ - Type size() const throw() - { - Type num = 0; + virtual bool undo() = 0; - for (int i = 0; i < values.size(); i += 2) - num += values[i + 1] - values[i]; + /** Returns a value to indicate how much memory this object takes up. - return num; - } + Because the UndoManager keeps a list of UndoableActions, this is used + to work out how much space each one will take up, so that the UndoManager + can work out how many to keep. - /** Returns one of the values in the set. + The default value returned here is 10 - units are arbitrary and + don't have to be accurate. - @param index the index of the value to retrieve, in the range 0 to (size() - 1). - @returns the value at this index, or 0 if it's out-of-range + @see UndoManager::getNumberOfUnitsTakenUpByStoredCommands, + UndoManager::setMaxNumberOfStoredUnits */ - Type operator[] (int index) const throw() - { - for (int i = 0; i < values.size(); i += 2) - { - const Type s = values.getUnchecked(i); - const Type e = values.getUnchecked(i + 1); + virtual int getSizeInUnits() { return 10; } +}; - if (index < e - s) - return s + index; +#endif // __JUCE_UNDOABLEACTION_JUCEHEADER__ +/********* End of inlined file: juce_UndoableAction.h *********/ - index -= e - s; - } +/** + Manages a list of undo/redo commands. - return (Type) 0; - } + An UndoManager object keeps a list of past actions and can use these actions + to move backwards and forwards through an undo history. - /** Checks whether a particular value is in the set. */ - bool contains (const Type valueToLookFor) const throw() - { - bool on = false; + To use it, create subclasses of UndoableAction which perform all the + actions you need, then when you need to actually perform an action, create one + and pass it to the UndoManager's perform() method. - for (int i = 0; i < values.size(); ++i) - { - if (values.getUnchecked(i) > valueToLookFor) - return on; + The manager also uses the concept of 'transactions' to group the actions + together - all actions performed between calls to beginNewTransaction() are + grouped together and are all undone/redone as a group. - on = ! on; - } + The UndoManager is a ChangeBroadcaster, so listeners can register to be told + when actions are performed or undone. - return false; - } + @see UndoableAction +*/ +class JUCE_API UndoManager : public ChangeBroadcaster +{ +public: - /** Returns the number of contiguous blocks of values. + /** Creates an UndoManager. - @see getRange + @param maxNumberOfUnitsToKeep each UndoableAction object returns a value + to indicate how much storage it takes up + (UndoableAction::getSizeInUnits()), so this + lets you specify the maximum total number of + units that the undomanager is allowed to + keep in memory before letting the older actions + drop off the end of the list. + @param minimumTransactionsToKeep this specifies the minimum number of transactions + that will be kept, even if this involves exceeding + the amount of space specified in maxNumberOfUnitsToKeep */ - int getNumRanges() const throw() - { - return values.size() >> 1; - } + UndoManager (const int maxNumberOfUnitsToKeep = 30000, + const int minimumTransactionsToKeep = 30); - /** Returns one of the contiguous ranges of values stored. + /** Destructor. */ + ~UndoManager(); - @param rangeIndex the index of the range to look up, between 0 - and (getNumRanges() - 1) - @param startValue on return, the value at the start of the range - @param numValues on return, the number of values in the range + /** Deletes all stored actions in the list. */ + void clearUndoHistory(); - @see getTotalRange + /** Returns the current amount of space to use for storing UndoableAction objects. + + @see setMaxNumberOfStoredUnits */ - bool getRange (const int rangeIndex, - Type& startValue, - Type& numValues) const throw() - { - if (((unsigned int) rangeIndex) < (unsigned int) getNumRanges()) - { - startValue = values [rangeIndex << 1]; - numValues = values [(rangeIndex << 1) + 1] - startValue; + int getNumberOfUnitsTakenUpByStoredCommands() const; - return true; - } + /** Sets the amount of space that can be used for storing UndoableAction objects. - return false; - } + @param maxNumberOfUnitsToKeep each UndoableAction object returns a value + to indicate how much storage it takes up + (UndoableAction::getSizeInUnits()), so this + lets you specify the maximum total number of + units that the undomanager is allowed to + keep in memory before letting the older actions + drop off the end of the list. + @param minimumTransactionsToKeep this specifies the minimum number of transactions + that will be kept, even if this involves exceeding + the amount of space specified in maxNumberOfUnitsToKeep + @see getNumberOfUnitsTakenUpByStoredCommands + */ + void setMaxNumberOfStoredUnits (const int maxNumberOfUnitsToKeep, + const int minimumTransactionsToKeep); - /** Returns the lowest and highest values in the set. + /** Performs an action and adds it to the undo history list. - @see getRange + @param action the action to perform - this will be deleted by the UndoManager + when no longer needed + @param actionName if this string is non-empty, the current transaction will be + given this name; if it's empty, the current transaction name will + be left unchanged. See setCurrentTransactionName() + @returns true if the command succeeds - see UndoableAction::perform + @see beginNewTransaction */ - bool getTotalRange (Type& lowestValue, - Type& highestValue) const throw() - { - if (values.size() > 0) - { - lowestValue = values.getUnchecked (0); - highestValue = values.getUnchecked (values.size() - 1); - return true; - } - - return false; - } + bool perform (UndoableAction* const action, + const String& actionName = String::empty); - /** Adds a range of contiguous values to the set. + /** Starts a new group of actions that together will be treated as a single transaction. - e.g. addRange (10, 4) will add (10, 11, 12, 13) to the set. + All actions that are passed to the perform() method between calls to this + method are grouped together and undone/redone together by a single call to + undo() or redo(). - @param firstValue the start of the range of values to add - @param numValuesToAdd how many values to add + @param actionName a description of the transaction that is about to be + performed */ - void addRange (const Type firstValue, - const Type numValuesToAdd) throw() - { - jassert (numValuesToAdd >= 0); + void beginNewTransaction (const String& actionName = String::empty); - if (numValuesToAdd > 0) - { - removeRange (firstValue, numValuesToAdd); + /** Changes the name stored for the current transaction. - IntegerElementComparator sorter; - values.addSorted (sorter, firstValue); - values.addSorted (sorter, firstValue + numValuesToAdd); + Each transaction is given a name when the beginNewTransaction() method is + called, but this can be used to change that name without starting a new + transaction. + */ + void setCurrentTransactionName (const String& newName); - simplify(); - } - } + /** Returns true if there's at least one action in the list to undo. - /** Removes a range of values from the set. + @see getUndoDescription, undo, canRedo + */ + bool canUndo() const; - e.g. removeRange (10, 4) will remove (10, 11, 12, 13) from the set. + /** Returns the description of the transaction that would be next to get undone. - @param firstValue the start of the range of values to remove - @param numValuesToRemove how many values to remove + The description returned is the one that was passed into beginNewTransaction + before the set of actions was performed. + + @see undo */ - void removeRange (const Type firstValue, - const Type numValuesToRemove) throw() - { - jassert (numValuesToRemove >= 0); + const String getUndoDescription() const; - if (numValuesToRemove >= 0 - && firstValue < values.getLast()) - { - const bool onAtStart = contains (firstValue - 1); - const Type lastValue = firstValue + jmin (numValuesToRemove, values.getLast() - firstValue); - const bool onAtEnd = contains (lastValue); + /** Tries to roll-back the last transaction. - for (int i = values.size(); --i >= 0;) - { - if (values.getUnchecked(i) <= lastValue) - { - while (values.getUnchecked(i) >= firstValue) - { - values.remove (i); + @returns true if the transaction can be undone, and false if it fails, or + if there aren't any transactions to undo + */ + bool undo(); - if (--i < 0) - break; - } + /** Tries to roll-back any actions that were added to the current transaction. - break; - } - } + This will perform an undo() only if there are some actions in the undo list + that were added after the last call to beginNewTransaction(). - IntegerElementComparator sorter; + This is useful because it lets you call beginNewTransaction(), then + perform an operation which may or may not actually perform some actions, and + then call this method to get rid of any actions that might have been done + without it rolling back the previous transaction if nothing was actually + done. - if (onAtStart) - values.addSorted (sorter, firstValue); + @returns true if any actions were undone. + */ + bool undoCurrentTransactionOnly(); - if (onAtEnd) - values.addSorted (sorter, lastValue); + /** Returns a list of the UndoableAction objects that have been performed during the + transaction that is currently open. - simplify(); - } - } + Effectively, this is the list of actions that would be undone if undoCurrentTransactionOnly() + were to be called now. - /** Does an XOR of the values in a given range. */ - void invertRange (const Type firstValue, - const Type numValues) - { - SparseSet newItems; - newItems.addRange (firstValue, numValues); + The first item in the list is the earliest action performed. + */ + void getActionsInCurrentTransaction (Array & actionsFound) const; - int i; - for (i = getNumRanges(); --i >= 0;) - { - const int start = values [i << 1]; - const int end = values [(i << 1) + 1]; + /** Returns true if there's at least one action in the list to redo. - newItems.removeRange (start, end); - } + @see getRedoDescription, redo, canUndo + */ + bool canRedo() const; - removeRange (firstValue, numValues); + /** Returns the description of the transaction that would be next to get redone. - for (i = newItems.getNumRanges(); --i >= 0;) - { - const int start = newItems.values [i << 1]; - const int end = newItems.values [(i << 1) + 1]; + The description returned is the one that was passed into beginNewTransaction + before the set of actions was performed. - addRange (start, end); - } - } + @see redo + */ + const String getRedoDescription() const; - /** Checks whether any part of a given range overlaps any part of this one. */ - bool overlapsRange (const Type firstValue, - const Type numValues) throw() - { - jassert (numValues >= 0); + /** Tries to redo the last transaction that was undone. - if (numValues > 0) - { - for (int i = getNumRanges(); --i >= 0;) - { - if (firstValue >= values.getUnchecked ((i << 1) + 1)) - return false; + @returns true if the transaction can be redone, and false if it fails, or + if there aren't any transactions to redo + */ + bool redo(); - if (firstValue + numValues > values.getUnchecked (i << 1)) - return true; - } - } + juce_UseDebuggingNewOperator - return false; - } +private: - /** Checks whether the whole of a given range is contained within this one. */ - bool containsRange (const Type firstValue, - const Type numValues) throw() - { - jassert (numValues >= 0); + OwnedArray > transactions; + StringArray transactionNames; + String currentTransactionName; + int totalUnitsStored, maxNumUnitsToKeep, minimumTransactionsToKeep, nextIndex; + bool newTransaction, reentrancyCheck; - if (numValues > 0) - { - for (int i = getNumRanges(); --i >= 0;) - { - if (firstValue >= values.getUnchecked ((i << 1) + 1)) - return false; - - if (firstValue >= values.getUnchecked (i << 1) - && firstValue + numValues <= values.getUnchecked ((i << 1) + 1)) - return true; - } - } - - return false; - } - - bool operator== (const SparseSet& other) throw() - { - return values == other.values; - } - - bool operator!= (const SparseSet& other) throw() - { - return values != other.values; - } - - juce_UseDebuggingNewOperator - -private: - // alternating start/end values of ranges of values that are present. - Array values; - - void simplify() throw() - { - jassert ((values.size() & 1) == 0); - - for (int i = values.size(); --i > 0;) - if (values.getUnchecked(i) == values.getUnchecked (i - 1)) - values.removeRange (i - 1, 2); - } + // disallow copy constructor + UndoManager (const UndoManager&); + const UndoManager& operator= (const UndoManager&); }; -#endif // __JUCE_SPARSESET_JUCEHEADER__ -/********* End of inlined file: juce_SparseSet.h *********/ - -#endif -#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ - -#endif -#ifndef __JUCE_VALUETREE_JUCEHEADER__ - -/********* Start of inlined file: juce_ValueTree.h *********/ -#ifndef __JUCE_VALUETREE_JUCEHEADER__ -#define __JUCE_VALUETREE_JUCEHEADER__ +#endif // __JUCE_UNDOMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_UndoManager.h *********/ -/********* Start of inlined file: juce_UndoManager.h *********/ -#ifndef __JUCE_UNDOMANAGER_JUCEHEADER__ -#define __JUCE_UNDOMANAGER_JUCEHEADER__ +/** + A powerful tree structure that can be used to hold free-form data, and which can + handle its own undo and redo behaviour. -/********* Start of inlined file: juce_ChangeBroadcaster.h *********/ -#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ -#define __JUCE_CHANGEBROADCASTER_JUCEHEADER__ + A ValueTree contains a list of named properties as var objects, and also holds + any number of sub-trees. -/********* Start of inlined file: juce_ChangeListenerList.h *********/ -#ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ -#define __JUCE_CHANGELISTENERLIST_JUCEHEADER__ + Create ValueTree objects on the stack, and don't be afraid to copy them around, as + they're simply a lightweight reference to a shared data container. Creating a copy + of another ValueTree simply creates a new reference to the same underlying object - to + make a separate, deep copy of a tree you should explicitly call createCopy(). -/********* Start of inlined file: juce_ChangeListener.h *********/ -#ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ -#define __JUCE_CHANGELISTENER_JUCEHEADER__ + Each ValueTree has a type name, in much the same way as an XmlElement has a tag name, + and much of the structure of a ValueTree is similar to an XmlElement tree. + You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't + contain text elements, the conversion works well and makes a good serialisation + format. They can also be serialised to a binary format, which is very fast and compact. -/** - Receives callbacks about changes to some kind of object. + All the methods that change data take an optional UndoManager, which will be used + to track any changes to the object. For this to work, you have to be careful to + consistently always use the same UndoManager for all operations to any node inside + the tree. - 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. + A ValueTree can only be a child of one parent at a time, so if you're moving one from + one tree to another, be careful to always remove it first, before adding it. This + could also mess up your undo/redo chain, so be wary! In a debug build you should hit + assertions if you try to do anything dangerous, but there are still plenty of ways it + could go wrong. - 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. + Listeners can be added to a ValueTree to be told when properies change and when + nodes are added or removed. - @see ChangeListenerList, ChangeBroadcaster, ActionListener + @see var, XmlElement */ -class JUCE_API ChangeListener +class JUCE_API ValueTree { public: - /** Destructor. */ - virtual ~ChangeListener() {} - - /** Overridden by your subclass to receive the callback. - @param objectThatHasChanged the value that was passed to the - ChangeListenerList::sendChangeMessage() method + /** Creates an empty ValueTree with the given type name. + Like an XmlElement, each ValueTree node has a type, which you can access with + getType() and hasType(). */ - virtual void changeListenerCallback (void* objectThatHasChanged) = 0; -}; - -#endif // __JUCE_CHANGELISTENER_JUCEHEADER__ -/********* End of inlined file: juce_ChangeListener.h *********/ + ValueTree (const String& type) throw(); -/********* Start of inlined file: juce_MessageListener.h *********/ -#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ -#define __JUCE_MESSAGELISTENER_JUCEHEADER__ + /** Creates a reference to another ValueTree. */ + ValueTree (const ValueTree& other) throw(); -/********* Start of inlined file: juce_Message.h *********/ -#ifndef __JUCE_MESSAGE_JUCEHEADER__ -#define __JUCE_MESSAGE_JUCEHEADER__ + /** Makes this object reference another node. */ + const ValueTree& operator= (const ValueTree& other) throw(); -class MessageListener; -class MessageManager; + /** Destructor. */ + ~ValueTree() throw(); -/** The base class for objects that can be delivered to a MessageListener. + /** Returns true if both this and the other tree node refer to the same underlying structure. + Note that this isn't a value comparison - two independently-created trees which + contain identical data are not considered equal. + */ + bool operator== (const ValueTree& other) const throw(); - The simplest Message object contains a few integer and pointer parameters - that the user can set, and this is enough for a lot of purposes. For passing more - complex data, subclasses of Message can also be used. + /** Returns true if this and the other node refer to different underlying structures. + Note that this isn't a value comparison - two independently-created trees which + contain identical data are not considered equal. + */ + bool operator!= (const ValueTree& other) const throw(); - @see MessageListener, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API Message -{ -public: + /** Returns true if this node refers to some valid data. + It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range + call to getChild(). + */ + bool isValid() const throw() { return object != 0; } - /** Creates an uninitialised message. + /** Returns a deep copy of this tree and all its sub-nodes. */ + ValueTree createCopy() const throw(); - The class's variables will also be left uninitialised. + /** Returns the type of this node. + The type is specified when the ValueTree is created. + @see hasType */ - Message() throw(); + const String getType() const throw(); - /** Creates a message object, filling in the member variables. + /** Returns true if the node has this type. + The comparison is case-sensitive. + */ + bool hasType (const String& typeName) const throw(); - The corresponding public member variables will be set from the parameters - passed in. + /** Returns the value of a named property. + If no such property has been set, this will return a void variant. + You can also use operator[] to get a property. + @see var, setProperty, hasProperty */ - Message (const int intParameter1, - const int intParameter2, - const int intParameter3, - void* const pointerParameter) throw(); + const var getProperty (const var::identifier& name) const throw(); - /** Destructor. */ - virtual ~Message() throw(); + /** Returns the value of a named property. + If no such property has been set, this will return a void variant. This is the same as + calling getProperty(). + @see getProperty + */ + const var operator[] (const var::identifier& name) const throw(); - // These values can be used for carrying simple data that the application needs to - // pass around. For more complex messages, just create a subclass. + /** Changes a named property of the node. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + @see var, getProperty, removeProperty + */ + void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); - int intParameter1; /**< user-defined integer value. */ - int intParameter2; /**< user-defined integer value. */ - int intParameter3; /**< user-defined integer value. */ - void* pointerParameter; /**< user-defined pointer value. */ + /** Returns true if the node contains a named property. */ + bool hasProperty (const var::identifier& name) const throw(); - juce_UseDebuggingNewOperator + /** Removes a property from the node. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + */ + void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); -private: - friend class MessageListener; - friend class MessageManager; - MessageListener* messageRecipient; + /** Removes all properties from the node. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + */ + void removeAllProperties (UndoManager* const undoManager) throw(); - Message (const Message&); - const Message& operator= (const Message&); -}; + /** Returns the total number of properties that the node contains. + @see getProperty. + */ + int getNumProperties() const throw(); -#endif // __JUCE_MESSAGE_JUCEHEADER__ -/********* End of inlined file: juce_Message.h *********/ + /** Returns the identifier of the property with a given index. + @see getNumProperties + */ + const var::identifier getPropertyName (int index) const throw(); -/** - MessageListener subclasses can post and receive Message objects. + /** Returns the number of child nodes belonging to this one. + @see getChild + */ + int getNumChildren() const throw(); - @see Message, MessageManager, ActionListener, ChangeListener -*/ -class JUCE_API MessageListener -{ -protected: + /** Returns one of this node's child nodes. + If the index is out of range, it'll return an invalid node. (See isValid() to find out + whether a node is valid). + */ + ValueTree getChild (int index) const throw(); - /** Creates a MessageListener. */ - MessageListener() throw(); + /** Looks for a child node with the speficied type name. + If no such node is found, it'll return an invalid node. (See isValid() to find out + whether a node is valid). + */ + ValueTree getChildWithName (const String& type) const throw(); -public: + /** Looks for the first child node that has the speficied property value. - /** Destructor. + This will scan the child nodes in order, until it finds one that has property that matches + the specified value. - When a MessageListener is deleted, it removes itself from a global list - of registered listeners, so that the isValidMessageListener() method - will no longer return true. + If no such node is found, it'll return an invalid node. (See isValid() to find out + whether a node is valid). */ - virtual ~MessageListener(); - - /** This is the callback method that receives incoming messages. + ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); - This is called by the MessageManager from its dispatch loop. + /** Adds a child to this node. - @see postMessage - */ - virtual void handleMessage (const Message& message) = 0; + Make sure that the child is removed from any former parent node before calling this, or + you'll hit an assertion. - /** Sends a message to the message queue, for asynchronous delivery to this listener - later on. + If the index is < 0 or greater than the current number of child nodes, the new node will + be added at the end of the list. - This method can be called safely by any thread. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + */ + void addChild (ValueTree child, int index, UndoManager* const undoManager) throw(); - @param message the message object to send - this will be deleted - automatically by the message queue, so don't keep any - references to it after calling this method. - @see handleMessage + /** Removes the specified child from this node's child-list. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. */ - void postMessage (Message* const message) const throw(); + void removeChild (ValueTree& child, UndoManager* const undoManager) throw(); - /** Checks whether this MessageListener has been deleted. + /** Removes a child from this node's child-list. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + */ + void removeChild (const int childIndex, UndoManager* const undoManager) throw(); - Although not foolproof, this method is safe to call on dangling or null - pointers. A list of active MessageListeners is kept internally, so this - checks whether the object is on this list or not. + /** Removes all child-nodes from this node. + If the undoManager parameter is non-null, its UndoManager::perform() method will be used, + so that this change can be undone. + */ + void removeAllChildren (UndoManager* const undoManager) throw(); - Note that it's possible to get a false-positive here, if an object is - deleted and another is subsequently created that happens to be at the - exact same memory location, but I can't think of a good way of avoiding - this. + /** Returns true if this node is anywhere below the specified parent node. + This returns true if the node is a child-of-a-child, as well as a direct child. */ - bool isValidMessageListener() const throw(); -}; + bool isAChildOf (const ValueTree& possibleParent) const throw(); -#endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ -/********* End of inlined file: juce_MessageListener.h *********/ + /** Returns the parent node that contains this one. + If the node has no parent, this will return an invalid node. (See isValid() to find out + whether a node is valid). + */ + ValueTree getParent() const throw(); -/** - A set of ChangeListeners. + /** Creates an XmlElement that holds a complete image of this node and all its children. - Listeners can be added and removed from the list, and change messages can be - broadcast to all the listeners. + If this node is invalid, this may return 0. Otherwise, the XML that is produced can + be used to recreate a similar node by calling fromXml() + @see fromXml + */ + XmlElement* createXml() const throw(); - @see ChangeListener, ChangeBroadcaster -*/ -class JUCE_API ChangeListenerList : public MessageListener -{ -public: + /** Tries to recreate a node from its XML representation. - /** Creates an empty list. */ - ChangeListenerList() throw(); + This isn't designed to cope with random XML data - for a sensible result, it should only + be fed XML that was created by the createXml() method. + */ + static ValueTree fromXml (const XmlElement& xml) throw(); - /** Destructor. */ - ~ChangeListenerList() throw(); + /** Stores this tree (and all its children) in a binary format. - /** Adds a listener to the list. + Once written, the data can be read back with readFromStream(). - (Trying to add a listener that's already on the list will have no effect). + It's much faster to load/save your tree in binary form than as XML, but + obviously isn't human-readable. */ - void addChangeListener (ChangeListener* const listener) throw(); - - /** Removes a listener from the list. + void writeToStream (OutputStream& output) throw(); - If the listener isn't on the list, this won't have any effect. + /** Reloads a tree from a stream that was written with writeToStream(). */ - void removeChangeListener (ChangeListener* const listener) throw(); - - /** Removes all listeners from the list. */ - void removeAllChangeListeners() throw(); - - /** Posts an asynchronous change message to all the listeners. - - If a message has already been sent and hasn't yet been delivered, this - method won't send another - in this way it coalesces multiple frequent - changes into fewer actual callbacks to the ChangeListeners. Contrast this - with the ActionListener, which posts a new event for every call to its - sendActionMessage() method. + static ValueTree readFromStream (InputStream& input) throw(); - Only listeners which are on the list when the change event is delivered - will receive the event - and this may include listeners that weren't on - the list when the change message was sent. + /** Listener class for events that happen to a ValueTree. - @param objectThatHasChanged this pointer is passed to the - ChangeListener::changeListenerCallback() method, - and can be any value the application needs - @see sendSynchronousChangeMessage + To get events from a ValueTree, make your class implement this interface, and use + ValueTree::addListener() and ValueTree::removeListener() to register it. */ - void sendChangeMessage (void* objectThatHasChanged) throw(); + class JUCE_API Listener + { + public: + /** Destructor. */ + virtual ~Listener() {} - /** This will synchronously callback all the ChangeListeners. + /** This method is called when one or more of the properties of this node have changed. */ + virtual void valueTreePropertyChanged (ValueTree& tree) = 0; - Use this if you need to synchronously force a call to all the - listeners' ChangeListener::changeListenerCallback() methods. - */ - void sendSynchronousChangeMessage (void* objectThatHasChanged); + /** 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; - /** If a change message has been sent but not yet dispatched, this will - use sendSynchronousChangeMessage() to make the callback immediately. - */ - void dispatchPendingMessages(); + /** This method is called when this node has been added or removed from a parent node. */ + virtual void valueTreeParentChanged() = 0; + }; - /** @internal */ - void handleMessage (const Message&); + /** Adds a listener to receive callbacks when this node is changed. */ + void addListener (Listener* listener) throw(); + + /** Removes a listener that was previously added with addListener(). */ + void removeListener (Listener* listener) throw(); juce_UseDebuggingNewOperator private: - SortedSet listeners; - CriticalSection lock; - void* lastChangedObject; - bool messagePending; + friend class ValueTreeSetPropertyAction; + friend class ValueTreeChildChangeAction; - ChangeListenerList (const ChangeListenerList&); - const ChangeListenerList& operator= (const ChangeListenerList&); -}; + class SharedObject : public ReferenceCountedObject + { + public: + SharedObject (const String& type) throw(); + SharedObject (const SharedObject& other) throw(); + ~SharedObject() throw(); -#endif // __JUCE_CHANGELISTENERLIST_JUCEHEADER__ -/********* End of inlined file: juce_ChangeListenerList.h *********/ + struct Property + { + Property (const var::identifier& name, const var& value) throw(); -/** Manages a list of ChangeListeners, and can send them messages. + var::identifier name; + var value; + }; - To quickly add methods to your class that can add/remove change - listeners and broadcast to them, you can derive from this. + const String type; + OwnedArray properties; + ReferenceCountedArray children; + SortedSet listeners; + SharedObject* parent; - @see ChangeListenerList, ChangeListener -*/ -class JUCE_API ChangeBroadcaster -{ -public: + void sendPropertyChangeMessage(); + void sendChildChangeMessage(); + void sendParentChangeMessage(); + const var getProperty (const var::identifier& name) const throw(); + void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); + bool hasProperty (const var::identifier& name) const throw(); + void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); + void removeAllProperties (UndoManager* const undoManager) throw(); + bool isAChildOf (const SharedObject* const possibleParent) const throw(); + ValueTree getChildWithName (const String& type) const throw(); + ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); + void addChild (SharedObject* child, int index, UndoManager* const undoManager) throw(); + void removeChild (const int childIndex, UndoManager* const undoManager) throw(); + void removeAllChildren (UndoManager* const undoManager) throw(); + XmlElement* createXml() const throw(); + }; - /** Creates an ChangeBroadcaster. */ - ChangeBroadcaster() throw(); + friend class SharedObject; - /** Destructor. */ - virtual ~ChangeBroadcaster(); + typedef ReferenceCountedObjectPtr SharedObjectPtr; - /** Adds a listener to the list. + ReferenceCountedObjectPtr object; - (Trying to add a listener that's already on the list will have no effect). - */ - void addChangeListener (ChangeListener* const listener) throw(); + ValueTree (SharedObject* const object_) throw(); +}; - /** Removes a listener from the list. +#endif // __JUCE_VALUETREE_JUCEHEADER__ +/********* End of inlined file: juce_ValueTree.h *********/ - If the listener isn't on the list, this won't have any effect. - */ - void removeChangeListener (ChangeListener* const listener) throw(); +#endif +#ifndef __JUCE_VARIANT_JUCEHEADER__ - /** Removes all listeners from the list. */ - void removeAllChangeListeners() throw(); +#endif +#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ - /** Broadcasts a change message to all the registered listeners. +/********* Start of inlined file: juce_VoidArray.h *********/ +#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ +#define __JUCE_VOIDARRAY_JUCEHEADER__ - The message will be delivered asynchronously by the event thread, so this - method will not directly call any of the listeners. For a synchronous - message, use sendSynchronousChangeMessage(). +/** + A typedef for an Array of void*'s. - @see ChangeListenerList::sendActionMessage - */ - void sendChangeMessage (void* objectThatHasChanged) throw(); + VoidArrays are used in various places throughout the library instead of + more strongly-typed arrays, to keep code-size low. +*/ +typedef Array VoidArray; - /** Sends a synchronous change message to all the registered listeners. +#endif // __JUCE_VOIDARRAY_JUCEHEADER__ +/********* End of inlined file: juce_VoidArray.h *********/ - @see ChangeListenerList::sendSynchronousChangeMessage - */ - void sendSynchronousChangeMessage (void* objectThatHasChanged); +#endif +#ifndef __JUCE_ATOMIC_JUCEHEADER__ - /** If a change message has been sent but not yet dispatched, this will - use sendSynchronousChangeMessage() to make the callback immediately. - */ - void dispatchPendingMessages(); +#endif +#ifndef __JUCE_DATACONVERSIONS_JUCEHEADER__ -private: - - ChangeListenerList changeListenerList; - - ChangeBroadcaster (const ChangeBroadcaster&); - const ChangeBroadcaster& operator= (const ChangeBroadcaster&); -}; - -#endif // __JUCE_CHANGEBROADCASTER_JUCEHEADER__ -/********* End of inlined file: juce_ChangeBroadcaster.h *********/ +#endif +#ifndef __JUCE_FILELOGGER_JUCEHEADER__ -/********* Start of inlined file: juce_UndoableAction.h *********/ -#ifndef __JUCE_UNDOABLEACTION_JUCEHEADER__ -#define __JUCE_UNDOABLEACTION_JUCEHEADER__ +/********* Start of inlined file: juce_FileLogger.h *********/ +#ifndef __JUCE_FILELOGGER_JUCEHEADER__ +#define __JUCE_FILELOGGER_JUCEHEADER__ /** - Used by the UndoManager class to store an action which can be done - and undone. + A simple implemenation of a Logger that writes to a file. - @see UndoManager + @see Logger */ -class JUCE_API UndoableAction +class JUCE_API FileLogger : public Logger { -protected: - /** Creates an action. */ - UndoableAction() throw() {} - public: - /** Destructor. */ - virtual ~UndoableAction() {} - /** Overridden by a subclass to perform the action. + /** Creates a FileLogger for a given file. - This method is called by the UndoManager, and shouldn't be used directly by - applications. + @param fileToWriteTo the file that to use - new messages will be appended + to the file. If the file doesn't exist, it will be created, + along with any parent directories that are needed. + @param welcomeMessage when opened, the logger will write a header to the log, along + with the current date and time, and this welcome message + @param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists + but is larger than this number of bytes, then the start of the + file will be truncated to keep the size down. This prevents a log + file getting ridiculously large over time. The file will be truncated + at a new-line boundary. If this value is less than zero, no size limit + will be imposed; if it's zero, the file will always be deleted. Note that + the size is only checked once when this object is created - any logging + that is done later will be appended without any checking + */ + FileLogger (const File& fileToWriteTo, + const String& welcomeMessage, + const int maxInitialFileSizeBytes = 128 * 1024); - Be careful not to make any calls in a perform() method that could call - recursively back into the UndoManager::perform() method + /** Destructor. */ + ~FileLogger(); - @returns true if the action could be performed. - @see UndoManager::perform - */ - virtual bool perform() = 0; + void logMessage (const String& message); - /** Overridden by a subclass to undo the action. + /** Helper function to create a log file in the correct place for this platform. - This method is called by the UndoManager, and shouldn't be used directly by - applications. + On Windows this will return a logger with a path such as: + c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName] - Be careful not to make any calls in an undo() method that could call - recursively back into the UndoManager::perform() method + On the Mac it'll create something like: + ~/Library/Logs/[logFileName] - @returns true if the action could be undone without any errors. - @see UndoManager::perform + The method might return 0 if the file can't be created for some reason. + + @param logFileSubDirectoryName if a subdirectory is needed, this is what it will be called - + it's best to use the something like the name of your application here. + @param logFileName the name of the file to create, e.g. "MyAppLog.txt". Don't just + call it "log.txt" because if it goes in a directory with logs + from other applications (as it will do on the Mac) then no-one + will know which one is yours! + @param welcomeMessage a message that will be written to the log when it's opened. + @param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this) */ - virtual bool undo() = 0; + static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName, + const String& logFileName, + const String& welcomeMessage, + const int maxInitialFileSizeBytes = 128 * 1024); - /** Returns a value to indicate how much memory this object takes up. + juce_UseDebuggingNewOperator - Because the UndoManager keeps a list of UndoableActions, this is used - to work out how much space each one will take up, so that the UndoManager - can work out how many to keep. +private: + File logFile; + CriticalSection logLock; + FileOutputStream* logStream; - The default value returned here is 10 - units are arbitrary and - don't have to be accurate. + void trimFileSize (int maxFileSizeBytes) const; - @see UndoManager::getNumberOfUnitsTakenUpByStoredCommands, - UndoManager::setMaxNumberOfStoredUnits - */ - virtual int getSizeInUnits() { return 10; } + FileLogger (const FileLogger&); + const FileLogger& operator= (const FileLogger&); }; -#endif // __JUCE_UNDOABLEACTION_JUCEHEADER__ -/********* End of inlined file: juce_UndoableAction.h *********/ +#endif // __JUCE_FILELOGGER_JUCEHEADER__ +/********* End of inlined file: juce_FileLogger.h *********/ -/** - Manages a list of undo/redo commands. +#endif +#ifndef __JUCE_INITIALISATION_JUCEHEADER__ - An UndoManager object keeps a list of past actions and can use these actions - to move backwards and forwards through an undo history. +/********* Start of inlined file: juce_Initialisation.h *********/ +#ifndef __JUCE_INITIALISATION_JUCEHEADER__ +#define __JUCE_INITIALISATION_JUCEHEADER__ - To use it, create subclasses of UndoableAction which perform all the - actions you need, then when you need to actually perform an action, create one - and pass it to the UndoManager's perform() method. +/** Initialises Juce's GUI classes. - The manager also uses the concept of 'transactions' to group the actions - together - all actions performed between calls to beginNewTransaction() are - grouped together and are all undone/redone as a group. + If you're embedding Juce into an application that uses its own event-loop rather + than using the START_JUCE_APPLICATION macro, call this function before making any + Juce calls, to make sure things are initialised correctly. - The UndoManager is a ChangeBroadcaster, so listeners can register to be told - when actions are performed or undone. + Note that if you're creating a Juce DLL for Windows, you may also need to call the + PlatformUtilities::setCurrentModuleInstanceHandle() method. - @see UndoableAction + @see shutdownJuce_GUI(), initialiseJuce_NonGUI() */ -class JUCE_API UndoManager : public ChangeBroadcaster -{ -public: - - /** Creates an UndoManager. +void JUCE_PUBLIC_FUNCTION initialiseJuce_GUI(); - @param maxNumberOfUnitsToKeep each UndoableAction object returns a value - to indicate how much storage it takes up - (UndoableAction::getSizeInUnits()), so this - lets you specify the maximum total number of - units that the undomanager is allowed to - keep in memory before letting the older actions - drop off the end of the list. - @param minimumTransactionsToKeep this specifies the minimum number of transactions - that will be kept, even if this involves exceeding - the amount of space specified in maxNumberOfUnitsToKeep - */ - UndoManager (const int maxNumberOfUnitsToKeep = 30000, - const int minimumTransactionsToKeep = 30); +/** Clears up any static data being used by Juce's GUI classes. - /** Destructor. */ - ~UndoManager(); + If you're embedding Juce into an application that uses its own event-loop rather + than using the START_JUCE_APPLICATION macro, call this function in your shutdown + code to clean up any juce objects that might be lying around. - /** Deletes all stored actions in the list. */ - void clearUndoHistory(); + @see initialiseJuce_GUI(), initialiseJuce_NonGUI() +*/ +void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI(); - /** Returns the current amount of space to use for storing UndoableAction objects. +/** Initialises the core parts of Juce. - @see setMaxNumberOfStoredUnits - */ - int getNumberOfUnitsTakenUpByStoredCommands() const; + If you're embedding Juce into either a command-line program, call this function + at the start of your main() function to make sure that Juce is initialised correctly. - /** Sets the amount of space that can be used for storing UndoableAction objects. + Note that if you're creating a Juce DLL for Windows, you may also need to call the + PlatformUtilities::setCurrentModuleInstanceHandle() method. - @param maxNumberOfUnitsToKeep each UndoableAction object returns a value - to indicate how much storage it takes up - (UndoableAction::getSizeInUnits()), so this - lets you specify the maximum total number of - units that the undomanager is allowed to - keep in memory before letting the older actions - drop off the end of the list. - @param minimumTransactionsToKeep this specifies the minimum number of transactions - that will be kept, even if this involves exceeding - the amount of space specified in maxNumberOfUnitsToKeep - @see getNumberOfUnitsTakenUpByStoredCommands - */ - void setMaxNumberOfStoredUnits (const int maxNumberOfUnitsToKeep, - const int minimumTransactionsToKeep); + @see shutdownJuce_NonGUI, initialiseJuce_GUI +*/ +void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI(); - /** Performs an action and adds it to the undo history list. +/** Clears up any static data being used by Juce's non-gui core classes. - @param action the action to perform - this will be deleted by the UndoManager - when no longer needed - @param actionName if this string is non-empty, the current transaction will be - given this name; if it's empty, the current transaction name will - be left unchanged. See setCurrentTransactionName() - @returns true if the command succeeds - see UndoableAction::perform - @see beginNewTransaction - */ - bool perform (UndoableAction* const action, - const String& actionName = String::empty); + If you're embedding Juce into either a command-line program, call this function + at the end of your main() function if you want to make sure any Juce objects are + cleaned up correctly. - /** Starts a new group of actions that together will be treated as a single transaction. + @see initialiseJuce_NonGUI, initialiseJuce_GUI +*/ +void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); - All actions that are passed to the perform() method between calls to this - method are grouped together and undone/redone together by a single call to - undo() or redo(). +#endif // __JUCE_INITIALISATION_JUCEHEADER__ +/********* End of inlined file: juce_Initialisation.h *********/ - @param actionName a description of the transaction that is about to be - performed - */ - void beginNewTransaction (const String& actionName = String::empty); +#endif +#ifndef __JUCE_LOGGER_JUCEHEADER__ - /** Changes the name stored for the current transaction. +#endif +#ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ - Each transaction is given a name when the beginNewTransaction() method is - called, but this can be used to change that name without starting a new - transaction. - */ - void setCurrentTransactionName (const String& newName); +#endif +#ifndef __JUCE_MEMORY_JUCEHEADER__ - /** Returns true if there's at least one action in the list to undo. +#endif +#ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ - @see getUndoDescription, undo, canRedo - */ - bool canUndo() const; +/********* Start of inlined file: juce_PerformanceCounter.h *********/ +#ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ +#define __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ - /** Returns the description of the transaction that would be next to get undone. +/** A timer for measuring performance of code and dumping the results to a file. - The description returned is the one that was passed into beginNewTransaction - before the set of actions was performed. + e.g. @code - @see undo - */ - const String getUndoDescription() const; + PerformanceCounter pc ("fish", 50, "/temp/myfishlog.txt"); - /** Tries to roll-back the last transaction. + for (;;) + { + pc.start(); - @returns true if the transaction can be undone, and false if it fails, or - if there aren't any transactions to undo - */ - bool undo(); + doSomethingFishy(); - /** Tries to roll-back any actions that were added to the current transaction. + pc.stop(); + } + @endcode - This will perform an undo() only if there are some actions in the undo list - that were added after the last call to beginNewTransaction(). + In this example, the time of each period between calling start/stop will be + measured and averaged over 50 runs, and the results printed to a file + every 50 times round the loop. +*/ +class JUCE_API PerformanceCounter +{ +public: - This is useful because it lets you call beginNewTransaction(), then - perform an operation which may or may not actually perform some actions, and - then call this method to get rid of any actions that might have been done - without it rolling back the previous transaction if nothing was actually - done. + /** Creates a PerformanceCounter object. - @returns true if any actions were undone. + @param counterName the name used when printing out the statistics + @param runsPerPrintout the number of start/stop iterations before calling + printStatistics() + @param loggingFile a file to dump the results to - if this is File::nonexistent, + the results are just written to the debugger output */ - bool undoCurrentTransactionOnly(); - - /** Returns a list of the UndoableAction objects that have been performed during the - transaction that is currently open. - - Effectively, this is the list of actions that would be undone if undoCurrentTransactionOnly() - were to be called now. + PerformanceCounter (const String& counterName, + int runsPerPrintout = 100, + const File& loggingFile = File::nonexistent); - The first item in the list is the earliest action performed. - */ - void getActionsInCurrentTransaction (Array & actionsFound) const; + /** Destructor. */ + ~PerformanceCounter(); - /** Returns true if there's at least one action in the list to redo. + /** Starts timing. - @see getRedoDescription, redo, canUndo + @see stop */ - bool canRedo() const; + void start(); - /** Returns the description of the transaction that would be next to get redone. + /** Stops timing and prints out the results. - The description returned is the one that was passed into beginNewTransaction - before the set of actions was performed. + The number of iterations before doing a printout of the + results is set in the constructor. - @see redo + @see start */ - const String getRedoDescription() const; + void stop(); - /** Tries to redo the last transaction that was undone. + /** Dumps the current metrics to the debugger output and to a file. - @returns true if the transaction can be redone, and false if it fails, or - if there aren't any transactions to redo + As well as using Logger::outputDebugString to print the results, + this will write then to the file specified in the constructor (if + this was valid). */ - bool redo(); + void printStatistics(); juce_UseDebuggingNewOperator private: - OwnedArray > transactions; - StringArray transactionNames; - String currentTransactionName; - int totalUnitsStored, maxNumUnitsToKeep, minimumTransactionsToKeep, nextIndex; - bool newTransaction, reentrancyCheck; - - // disallow copy constructor - UndoManager (const UndoManager&); - const UndoManager& operator= (const UndoManager&); + String name; + int numRuns, runsPerPrint; + double totalTime; + int64 started; + File outputFile; }; -#endif // __JUCE_UNDOMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_UndoManager.h *********/ - -/** - A powerful tree structure that can be used to hold free-form data, and which can - handle its own undo and redo behaviour. - - A ValueTree contains a list of named properties as var objects, and also holds - any number of sub-trees. - - Create ValueTree objects on the stack, and don't be afraid to copy them around, as - they are simply a lightweight reference to a shared data container. Creating a copy - of another ValueTree simply creates a new reference to the same underlying object - to - make a separate, deep copy of a tree you should explicitly call createCopy(). +#endif // __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ +/********* End of inlined file: juce_PerformanceCounter.h *********/ - Each ValueTree has a type name, in much the same way as an XmlElement has a tag name, - and much of the structure of a ValueTree is similar to an XmlElement tree. - You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't - contain text elements, the conversion works well and makes a good serialisation - format. +#endif +#ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ - All the methods that change data take an optional UndoManager, which will be used - to track any changes to the object. For this to work, you have to be careful to - consistently always use the same UndoManager for all operations to any node inside - the tree. +#endif +#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ - Nodes can only be a child of one parent at a time, so if you're moving a node from - one tree to another, be careful to always remove it first, before adding it. This - could also mess up your undo/redo chain, so be wary! +/********* Start of inlined file: juce_PlatformUtilities.h *********/ +#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ +#define __JUCE_PLATFORMUTILITIES_JUCEHEADER__ - Listeners can be added to a ValueTree to be told when properies change and when - nodes are added or removed. +/** + A collection of miscellaneous platform-specific utilities. - @see var, XmlElement */ -class JUCE_API ValueTree +class JUCE_API PlatformUtilities { public: - /** Creates an empty ValueTree with the given type name. - Like an XmlElement, each ValueTree node has a type, which you can access with - getType() and hasType(). - */ - ValueTree (const String& type) throw(); - - /** Creates a reference to another ValueTree. */ - ValueTree (const ValueTree& other) throw(); + /** Plays the operating system's default alert 'beep' sound. */ + static void beep(); - /** Makes this object reference another node. */ - const ValueTree& operator= (const ValueTree& other) throw(); + static bool launchEmailWithAttachments (const String& targetEmailAddress, + const String& emailSubject, + const String& bodyText, + const StringArray& filesToAttach); - /** Destructor. */ - ~ValueTree() throw(); +#if JUCE_MAC || JUCE_IPHONE || DOXYGEN - /** Returns true if both this and the other tree node refer to the same underlying structure. - Note that this isn't a value comparison - two independently-created trees which - contain identical data are not considered equal. - */ - bool operator== (const ValueTree& other) const throw(); + /** MAC ONLY - Turns a Core CF String into a juce one. */ + static const String cfStringToJuceString (CFStringRef cfString); - /** Returns true if this and the other node refer to different underlying structures. - Note that this isn't a value comparison - two independently-created trees which - contain identical data are not considered equal. - */ - bool operator!= (const ValueTree& other) const throw(); + /** MAC ONLY - Turns a juce string into a Core CF one. */ + static CFStringRef juceStringToCFString (const String& s); - /** Returns true if this node refers to some valid data. - It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range - call to getChild(). - */ - bool isValid() const throw() { return object != 0; } + /** MAC ONLY - Turns a file path into an FSRef, returning true if it succeeds. */ + static bool makeFSRefFromPath (FSRef* destFSRef, const String& path); - /** Returns a deep copy of this tree and all its sub-nodes. */ - ValueTree createCopy() const throw(); + /** MAC ONLY - Turns an FSRef into a juce string path. */ + static const String makePathFromFSRef (FSRef* file); - /** Returns the type of this node. - The type is specified when the ValueTree is created. - @see hasType + /** MAC ONLY - Converts any decomposed unicode characters in a string into + their precomposed equivalents. */ - const String getType() const throw(); + static const String convertToPrecomposedUnicode (const String& s); - /** Returns true if the node has this type. - The comparison is case-sensitive. - */ - bool hasType (const String& typeName) const throw(); + /** MAC ONLY - Gets the type of a file from the file's resources. */ + static OSType getTypeOfFile (const String& filename); - /** Returns the value of a named property. - If no such property has been set, this will return a void variant. - You can also use operator[] to get a property. - @see var, setProperty, hasProperty - */ - const var getProperty (const var::identifier& name) const throw(); + /** MAC ONLY - Returns true if this file is actually a bundle. */ + static bool isBundle (const String& filename); - /** Returns the value of a named property. - If no such property has been set, this will return a void variant. This is the same as - calling getProperty(). - @see getProperty - */ - const var operator[] (const var::identifier& name) const throw(); + /** MAC ONLY - Adds an item to the dock */ + static void addItemToDock (const File& file); - /** Changes a named property of the node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - @see var, getProperty, removeProperty + /** MAC ONLY - Returns the current OS version number. + E.g. if it's running on 10.4, this will be 4, 10.5 will return 5, etc. */ - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); + static int getOSXMinorVersionNumber() throw(); +#endif - /** Returns true if the node contains a named property. */ - bool hasProperty (const var::identifier& name) const throw(); +#if JUCE_WINDOWS || DOXYGEN - /** Removes a property from the node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); + // Some registry helper functions: - /** Removes all properties from the node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeAllProperties (UndoManager* const undoManager) throw(); + /** WIN32 ONLY - Returns a string from the registry. - /** Returns the total number of properties that the node contains. - @see getProperty. + The path is a string for the entire path of a value in the registry, + e.g. "HKEY_CURRENT_USER\Software\foo\bar" */ - int getNumProperties() const throw(); + static const String getRegistryValue (const String& regValuePath, + const String& defaultValue = String::empty); - /** Returns the identifier of the property with a given index. - @see getNumProperties - */ - const var::identifier getPropertyName (int index) const throw(); + /** WIN32 ONLY - Sets a registry value as a string. - /** Returns the number of child nodes belonging to this one. - @see getChild + This will take care of creating any groups needed to get to the given + registry value. */ - int getNumChildren() const throw(); + static void setRegistryValue (const String& regValuePath, + const String& value); - /** Returns one of this node's child nodes. - If the index is out of range, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getChild (int index) const throw(); + /** WIN32 ONLY - Returns true if the given value exists in the registry. */ + static bool registryValueExists (const String& regValuePath); - /** Looks for a child node with the speficied type name. - If no such node is found, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getChildWithName (const String& type) const throw(); + /** WIN32 ONLY - Deletes a registry value. */ + static void deleteRegistryValue (const String& regValuePath); - /** Looks for the first child node that has the speficied property value. + /** WIN32 ONLY - Deletes a registry key (which is registry-talk for 'folder'). */ + static void deleteRegistryKey (const String& regKeyPath); - This will scan the child nodes in order, until it finds one that has property that matches - the specified value. + /** WIN32 ONLY - Creates a file association in the registry. - If no such node is found, it'll return an invalid node. (See isValid() to find out - whether a node is valid). - */ - ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); - - /** Adds a child to this node. - - Make sure that the child is removed from any former parent node before calling this, or - you'll hit an assertion. - - If the index is < 0 or greater than the current number of child nodes, the new node will - be added at the end of the list. - - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. + This lets you set the exe that should be launched by a given file extension. + @param fileExtension the file extension to associate, including the + initial dot, e.g. ".txt" + @param symbolicDescription a space-free short token to identify the file type + @param fullDescription a human-readable description of the file type + @param targetExecutable the executable that should be launched + @param iconResourceNumber the icon that gets displayed for the file type will be + found by looking up this resource number in the + executable. Pass 0 here to not use an icon */ - void addChild (ValueTree child, int index, UndoManager* const undoManager) throw(); + static void registerFileAssociation (const String& fileExtension, + const String& symbolicDescription, + const String& fullDescription, + const File& targetExecutable, + int iconResourceNumber); - /** Removes the specified child from this node's child-list. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeChild (ValueTree& child, UndoManager* const undoManager) throw(); + /** WIN32 ONLY - This returns the HINSTANCE of the current module. - /** Removes a child from this node's child-list. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. - */ - void removeChild (const int childIndex, UndoManager* const undoManager) throw(); + In a normal Juce application this will be set to the module handle + of the application executable. - /** Removes all child-nodes from this node. - If the undoManager parameter is non-null, its UndoManager::perform() method will be used, - so that this change can be undone. + If you're writing a DLL using Juce and plan to use any Juce messaging or + windows, you'll need to make sure you use the setCurrentModuleInstanceHandle() + to set the correct module handle in your DllMain() function, because + the win32 system relies on the correct instance handle when opening windows. */ - void removeAllChildren (UndoManager* const undoManager) throw(); + static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() throw(); - /** Returns true if this node is anywhere below the specified parent node. - This returns true if the node is a child-of-a-child, as well as a direct child. - */ - bool isAChildOf (const ValueTree& possibleParent) const throw(); + /** WIN32 ONLY - Sets a new module handle to be used by the library. - /** Returns the parent node that contains this one. - If the node has no parent, this will return an invalid node. (See isValid() to find out - whether a node is valid). + @see getCurrentModuleInstanceHandle() */ - ValueTree getParent() const throw(); + static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) throw(); - /** Creates an XmlElement that holds a complete image of this node and all its children. + /** WIN32 ONLY - Gets the command-line params as a string. - If this node is invalid, this may return 0. Otherwise, the XML that is produced can - be used to recreate a similar node by calling fromXml() - @see fromXml + This is needed to avoid unicode problems with the argc type params. */ - XmlElement* createXml() const throw(); + static const String JUCE_CALLTYPE getCurrentCommandLineParams() throw(); +#endif - /** Tries to recreate a node from its XML representation. + /** Clears the floating point unit's flags. - 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. + Only has an effect under win32, currently. */ - static ValueTree fromXml (const XmlElement& xml) throw(); - - /** Stores this tree (and all its children) in a binary format. + static void fpuReset(); - Once written, the data can be read back with readFromStream(). +#if JUCE_LINUX || JUCE_WINDOWS - It's much faster to load/save your tree in binary form than as XML, but - obviously isn't human-readable. - */ - void writeToStream (OutputStream& output) throw(); + /** Loads a dynamically-linked library into the process's address space. - /** Reloads a tree from a stream that was written with writeToStream(). + @param pathOrFilename the platform-dependent name and search path + @returns a handle which can be used by getProcedureEntryPoint(), or + zero if it fails. + @see freeDynamicLibrary, getProcedureEntryPoint */ - static ValueTree readFromStream (InputStream& input) throw(); + static void* loadDynamicLibrary (const String& pathOrFilename); - /** Listener class for events that happen to a ValueTree. + /** Frees a dynamically-linked library. - To get events from a ValueTree, make your class implement this interface, and use - ValueTree::addListener() and ValueTree::removeListener() to register it. + @param libraryHandle a handle created by loadDynamicLibrary + @see loadDynamicLibrary, getProcedureEntryPoint */ - class JUCE_API Listener - { - public: - /** Destructor. */ - virtual ~Listener() {} + static void freeDynamicLibrary (void* libraryHandle); - /** This method is called when one or more of the properties of this node have changed. */ - virtual void valueTreePropertyChanged (ValueTree& tree) = 0; + /** Finds a procedure call in a dynamically-linked library. - /** 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; + @param libraryHandle a library handle returned by loadDynamicLibrary + @param procedureName the name of the procedure call to try to load + @returns a pointer to the function if found, or 0 if it fails + @see loadDynamicLibrary + */ + static void* getProcedureEntryPoint (void* libraryHandle, + const String& procedureName); +#endif - /** This method is called when this node has been added or removed from a parent node. */ - virtual void valueTreeParentChanged() = 0; - }; +#if JUCE_LINUX || DOXYGEN - /** Adds a listener to receive callbacks when this node is changed. */ - void addListener (Listener* listener) throw(); +#endif +}; - /** Removes a listener that was previously added with addListener(). */ - void removeListener (Listener* listener) throw(); +#if JUCE_MAC || JUCE_IPHONE - juce_UseDebuggingNewOperator +/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object + using RAII. +*/ +class ScopedAutoReleasePool +{ +public: + ScopedAutoReleasePool(); + ~ScopedAutoReleasePool(); private: - friend class ValueTreeSetPropertyAction; - friend class ValueTreeChildChangeAction; - - class SharedObject : public ReferenceCountedObject - { - public: - SharedObject (const String& type) throw(); - SharedObject (const SharedObject& other) throw(); - ~SharedObject() throw(); - - struct Property - { - Property (const var::identifier& name, const var& value) throw(); - - var::identifier name; - var value; - }; - - const String type; - OwnedArray properties; - ReferenceCountedArray children; - SortedSet listeners; - SharedObject* parent; - - void sendPropertyChangeMessage(); - void sendChildChangeMessage(); - void sendParentChangeMessage(); - const var getProperty (const var::identifier& name) const throw(); - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager) throw(); - bool hasProperty (const var::identifier& name) const throw(); - void removeProperty (const var::identifier& name, UndoManager* const undoManager) throw(); - void removeAllProperties (UndoManager* const undoManager) throw(); - bool isAChildOf (const SharedObject* const possibleParent) const throw(); - ValueTree getChildWithName (const String& type) const throw(); - ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const throw(); - void addChild (SharedObject* child, int index, UndoManager* const undoManager) throw(); - void removeChild (const int childIndex, UndoManager* const undoManager) throw(); - void removeAllChildren (UndoManager* const undoManager) throw(); - XmlElement* createXml() const throw(); - }; - - friend class SharedObject; - - typedef ReferenceCountedObjectPtr SharedObjectPtr; - - ReferenceCountedObjectPtr object; + void* pool; - ValueTree (SharedObject* const object_) throw(); + ScopedAutoReleasePool (const ScopedAutoReleasePool&); + const ScopedAutoReleasePool& operator= (const ScopedAutoReleasePool&); }; -#endif // __JUCE_VALUETREE_JUCEHEADER__ -/********* End of inlined file: juce_ValueTree.h *********/ - #endif -#ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ -/********* Start of inlined file: juce_DirectoryIterator.h *********/ -#ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ -#define __JUCE_DIRECTORYITERATOR_JUCEHEADER__ +#if JUCE_MAC /** - Searches through a the files in a directory, returning each file that is found. - - A DirectoryIterator will search through a directory and its subdirectories using - a wildcard filepattern match. - - If you may be finding a large number of files, this is better than - using File::findChildFiles() because it doesn't block while it finds them - all, and this is more memory-efficient. + A wrapper class for picking up events from an Apple IR remote control device. - It can also guess how far it's got using a wildly inaccurate algorithm. + To use it, just create a subclass of this class, implementing the buttonPressed() + callback, then call start() and stop() to start or stop receiving events. */ -class JUCE_API DirectoryIterator +class JUCE_API AppleRemoteDevice { public: - /** Creates a DirectoryIterator for a given directory. - - After creating one of these, call its next() method to get the - first file - e.g. @code + AppleRemoteDevice(); + virtual ~AppleRemoteDevice(); - DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose"); + /** The set of buttons that may be pressed. + @see buttonPressed + */ + enum ButtonType + { + menuButton = 0, /**< The menu button (if it's held for a short time). */ + playButton, /**< The play button. */ + plusButton, /**< The plus or volume-up button. */ + minusButton, /**< The minus or volume-down button. */ + rightButton, /**< The right button (if it's held for a short time). */ + leftButton, /**< The left button (if it's held for a short time). */ + rightButton_Long, /**< The right button (if it's held for a long time). */ + leftButton_Long, /**< The menu button (if it's held for a long time). */ + menuButton_Long, /**< The menu button (if it's held for a long time). */ + playButtonSleepMode, + switched + }; - while (iter.next()) - { - File theFileItFound (iter.getFile()); + /** Override this method to receive the callback about a button press. - ... etc - } - @endcode + The callback will happen on the application's message thread. - @param directory the directory to search in - @param isRecursive whether all the subdirectories should also be searched - @param wildCard the file pattern to match - @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying - whether to look for files, directories, or both. + Some buttons trigger matching up and down events, in which the isDown parameter + will be true and then false. Others only send a single event when the + button is pressed. */ - DirectoryIterator (const File& directory, - bool isRecursive, - const String& wildCard = JUCE_T("*"), - const int whatToLookFor = File::findFiles) throw(); + virtual void buttonPressed (const ButtonType buttonId, const bool isDown) = 0; - /** Destructor. */ - ~DirectoryIterator() throw(); + /** Starts the device running and responding to events. - /** Call this to move the iterator along to the next file. + Returns true if it managed to open the device. - @returns true if a file was found (you can then use getFile() to see what it was) - or - false if there are no more matching files. + @param inExclusiveMode if true, the remote will be grabbed exclusively for this app, + and will not be available to any other part of the system. If + false, it will be shared with other apps. + @see stop */ - bool next() throw(); - - /** Returns the file that the iterator is currently pointing at. + bool start (const bool inExclusiveMode) throw(); - The result of this call is only valid after a call to next() has returned true. + /** Stops the device running. + @see start */ - const File getFile() const throw(); + void stop() throw(); - /** Returns a guess of how far through the search the iterator has got. + /** Returns true if the device has been started successfully. + */ + bool isActive() const throw(); - @returns a value 0.0 to 1.0 to show the progress, although this won't be - very accurate. + /** Returns the ID number of the remote, if it has sent one. */ - float getEstimatedProgress() const throw(); + int getRemoteId() const throw() { return remoteId; } juce_UseDebuggingNewOperator + /** @internal */ + void handleCallbackInternal(); + private: - OwnedArray filesFound; - OwnedArray dirsFound; - String wildCard; - int index; - const int whatToLookFor; - DirectoryIterator* subIterator; + void* device; + void* queue; + int remoteId; - DirectoryIterator (const DirectoryIterator&); - const DirectoryIterator& operator= (const DirectoryIterator&); -}; + bool open (const bool openInExclusiveMode) throw(); -#endif // __JUCE_DIRECTORYITERATOR_JUCEHEADER__ -/********* End of inlined file: juce_DirectoryIterator.h *********/ + AppleRemoteDevice (const AppleRemoteDevice&); + const AppleRemoteDevice& operator= (const AppleRemoteDevice&); +}; #endif -#ifndef __JUCE_FILE_JUCEHEADER__ + +#endif // __JUCE_PLATFORMUTILITIES_JUCEHEADER__ +/********* End of inlined file: juce_PlatformUtilities.h *********/ #endif -#ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ +#ifndef __JUCE_RANDOM_JUCEHEADER__ -/********* Start of inlined file: juce_FileInputStream.h *********/ -#ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ -#define __JUCE_FILEINPUTSTREAM_JUCEHEADER__ +/********* Start of inlined file: juce_Random.h *********/ +#ifndef __JUCE_RANDOM_JUCEHEADER__ +#define __JUCE_RANDOM_JUCEHEADER__ /** - An input stream that reads from a local file. - - @see InputStream, FileOutputStream, File::createInputStream + A simple pseudo-random number generator. */ -class JUCE_API FileInputStream : public InputStream +class JUCE_API Random { public: - /** Creates a FileInputStream. + /** Creates a Random object based on a seed value. - @param fileToRead the file to read from - if the file can't be accessed for some - reason, then the stream will just contain no data + For a given seed value, the subsequent numbers generated by this object + will be predictable, so a good idea is to set this value based + on the time, e.g. + + new Random (Time::currentTimeMillis()) */ - FileInputStream (const File& fileToRead); + Random (const int64 seedValue) throw(); /** Destructor. */ - ~FileInputStream(); - - const File& getFile() const throw() { return file; } + ~Random() throw(); - int64 getTotalLength(); - int read (void* destBuffer, int maxBytesToRead); - bool isExhausted(); - int64 getPosition(); - bool setPosition (int64 pos); + /** Returns the next random 32 bit integer. - juce_UseDebuggingNewOperator + @returns a random integer from the full range 0x80000000 to 0x7fffffff + */ + int nextInt() throw(); -private: - File file; - void* fileHandle; - int64 currentPosition, totalSize; - bool needToSeek; + /** Returns the next random number, limited to a given range. - FileInputStream (const FileInputStream&); - const FileInputStream& operator= (const FileInputStream&); -}; + @returns a random integer between 0 (inclusive) and maxValue (exclusive). + */ + int nextInt (const int maxValue) throw(); -#endif // __JUCE_FILEINPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_FileInputStream.h *********/ + /** Returns the next 64-bit random number. -#endif -#ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ + @returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff + */ + int64 nextInt64() throw(); -/********* Start of inlined file: juce_FileOutputStream.h *********/ -#ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ -#define __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ + /** Returns the next random floating-point number. -/** - An output stream that writes into a local file. + @returns a random value in the range 0 to 1.0 + */ + float nextFloat() throw(); - @see OutputStream, FileInputStream, File::createOutputStream -*/ -class JUCE_API FileOutputStream : public OutputStream -{ -public: + /** Returns the next random floating-point number. - /** Creates a FileOutputStream. + @returns a random value in the range 0 to 1.0 + */ + double nextDouble() throw(); - If the file doesn't exist, it will first be created. If the file can't be - created or opened, the failedToOpen() method will return - true. + /** Returns the next random boolean value. + */ + bool nextBool() throw(); - If the file already exists when opened, the stream's write-postion will - be set to the end of the file. To overwrite an existing file, - use File::deleteFile() before opening the stream, or use setPosition(0) - after it's opened (although this won't truncate the file). + /** Returns a BitArray containing a random number. - It's better to use File::createOutputStream() to create one of these, rather - than using the class directly. + @returns a random value in the range 0 to (maximumValue - 1). */ - FileOutputStream (const File& fileToWriteTo, - const int bufferSizeToUse = 16384); + const BitArray nextLargeNumber (const BitArray& maximumValue) throw(); - /** Destructor. */ - ~FileOutputStream(); + /** Sets a range of bits in a BitArray to random values. */ + void fillBitsRandomly (BitArray& arrayToChange, int startBit, int numBits) throw(); - /** Returns the file that this stream is writing to. - */ - const File& getFile() const throw() { return file; } + /** To avoid the overhead of having to create a new Random object whenever + you need a number, this is a shared application-wide object that + can be used. - /** Returns true if the stream couldn't be opened for some reason. + It's not thread-safe though, so threads should use their own Random object. */ - bool failedToOpen() const throw() { return fileHandle == 0; } + static Random& getSystemRandom() throw(); - void flush(); - int64 getPosition(); - bool setPosition (int64 pos); - bool write (const void* data, int numBytes); + /** Resets this Random object to a given seed value. */ + void setSeed (const int64 newSeed) throw(); + + /** Reseeds this generator using a value generated from various semi-random system + properties like the current time, etc. + + Because this function convolves the time with the last seed value, calling + it repeatedly will increase the randomness of the final result. + */ + void setSeedRandomly(); juce_UseDebuggingNewOperator private: - File file; - void* fileHandle; - int64 currentPosition; - int bufferSize, bytesInBuffer; - char* buffer; + int64 seed; }; -#endif // __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_FileOutputStream.h *********/ +#endif // __JUCE_RANDOM_JUCEHEADER__ +/********* End of inlined file: juce_Random.h *********/ #endif -#ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ +#ifndef __JUCE_RELATIVETIME_JUCEHEADER__ -/********* Start of inlined file: juce_FileSearchPath.h *********/ -#ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ -#define __JUCE_FILESEARCHPATH_JUCEHEADER__ +#endif +#ifndef __JUCE_SINGLETON_JUCEHEADER__ + +/********* Start of inlined file: juce_Singleton.h *********/ +#ifndef __JUCE_SINGLETON_JUCEHEADER__ +#define __JUCE_SINGLETON_JUCEHEADER__ /** - Encapsulates a set of folders that make up a search path. + Macro to declare member variables and methods for a singleton class. - @see File -*/ -class JUCE_API FileSearchPath -{ -public: + To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion) + to the class's definition. - /** Creates an empty search path. */ - FileSearchPath(); + Then put a macro juce_ImplementSingleton (MyClass) along with the class's + implementation code. - /** Creates a search path from a string of pathnames. + It's also a very good idea to also add the call clearSingletonInstance() in your class's + destructor, in case it is deleted by other means than deleteInstance() - The path can be semicolon- or comma-separated, e.g. - "/foo/bar;/foo/moose;/fish/moose" + Clients can then call the static method MyClass::getInstance() to get a pointer + to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if + no instance currently exists. - The separate folders are tokenised and added to the search path. - */ - FileSearchPath (const String& path); + e.g. @code - /** Creates a copy of another search path. */ - FileSearchPath (const FileSearchPath& other); + class MySingleton + { + public: + MySingleton() + { + } - /** Destructor. */ - ~FileSearchPath(); + ~MySingleton() + { + // this ensures that no dangling pointers are left when the + // singleton is deleted. + clearSingletonInstance(); + } - /** Uses a string containing a list of pathnames to re-initialise this list. + juce_DeclareSingleton (MySingleton, false) + }; - This search path is cleared and the semicolon- or comma-separated folders - in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose" - */ - const FileSearchPath& operator= (const String& path); + juce_ImplementSingleton (MySingleton) - /** Returns the number of folders in this search path. + // example of usage: + MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one. - @see operator[] - */ - int getNumPaths() const; + ... - /** Returns one of the folders in this search path. + MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created). - The file returned isn't guaranteed to actually be a valid directory. - - @see getNumPaths - */ - const File operator[] (const int index) const; - - /** Returns the search path as a semicolon-separated list of directories. */ - const String toString() const; - - /** Adds a new directory to the search path. - - The new directory is added to the end of the list if the insertIndex parameter is - less than zero, otherwise it is inserted at the given index. - */ - void add (const File& directoryToAdd, - const int insertIndex = -1); + @endcode - /** Adds a new directory to the search path if it's not already in there. */ - void addIfNotAlreadyThere (const File& directoryToAdd); + If doNotRecreateAfterDeletion = true, it won't allow the object to be created more + than once during the process's lifetime - i.e. after you've created and deleted the + object, getInstance() will refuse to create another one. This can be useful to stop + objects being accidentally re-created during your app's shutdown code. - /** Removes a directory from the search path. */ - void remove (const int indexToRemove); + If you know that your object will only be created and deleted by a single thread, you + can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead + of this one. - /** Merges another search path into this one. + @see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded +*/ +#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \ +\ + static classname* _singletonInstance; \ + static JUCE_NAMESPACE::CriticalSection _singletonLock; \ +\ + static classname* getInstance() \ + { \ + if (_singletonInstance == 0) \ + {\ + const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ +\ + if (_singletonInstance == 0) \ + { \ + static bool alreadyInside = false; \ + static bool createdOnceAlready = false; \ +\ + const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ + jassert (! problem); \ + if (! problem) \ + { \ + createdOnceAlready = true; \ + alreadyInside = true; \ + classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ + alreadyInside = false; \ +\ + _singletonInstance = newObject; \ + } \ + } \ + } \ +\ + return _singletonInstance; \ + } \ +\ + static inline classname* getInstanceWithoutCreating() throw() \ + { \ + return _singletonInstance; \ + } \ +\ + static void deleteInstance() \ + { \ + const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ + if (_singletonInstance != 0) \ + { \ + classname* const old = _singletonInstance; \ + _singletonInstance = 0; \ + delete old; \ + } \ + } \ +\ + void clearSingletonInstance() throw() \ + { \ + if (_singletonInstance == this) \ + _singletonInstance = 0; \ + } - This will remove any duplicate directories. - */ - void addPath (const FileSearchPath& other); +/** This is a counterpart to the juce_DeclareSingleton macro. - /** Removes any directories that are actually subdirectories of one of the other directories in the search path. + After adding the juce_DeclareSingleton to the class definition, this macro has + to be used in the cpp file. +*/ +#define juce_ImplementSingleton(classname) \ +\ + classname* classname::_singletonInstance = 0; \ + JUCE_NAMESPACE::CriticalSection classname::_singletonLock; - If the search is intended to be recursive, there's no point having nested folders in the search - path, because they'll just get searched twice and you'll get duplicate results. +/** + Macro to declare member variables and methods for a singleton class. - e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc" - */ - void removeRedundantPaths(); + This is exactly the same as juce_DeclareSingleton, but doesn't use a critical + section to make access to it thread-safe. If you know that your object will + only ever be created or deleted by a single thread, then this is a + more efficient version to use. - /** Removes any directories that don't actually exist. */ - void removeNonExistentPaths(); + If doNotRecreateAfterDeletion = true, it won't allow the object to be created more + than once during the process's lifetime - i.e. after you've created and deleted the + object, getInstance() will refuse to create another one. This can be useful to stop + objects being accidentally re-created during your app's shutdown code. - /** Searches the path for a wildcard. + See the documentation for juce_DeclareSingleton for more information about + how to use it, the only difference being that you have to use + juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. - This will search all the directories in the search path in order, adding any - matching files to the results array. + @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal +*/ +#define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \ +\ + static classname* _singletonInstance; \ +\ + static classname* getInstance() \ + { \ + if (_singletonInstance == 0) \ + { \ + static bool alreadyInside = false; \ + static bool createdOnceAlready = false; \ +\ + const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ + jassert (! problem); \ + if (! problem) \ + { \ + createdOnceAlready = true; \ + alreadyInside = true; \ + classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ + alreadyInside = false; \ +\ + _singletonInstance = newObject; \ + } \ + } \ +\ + return _singletonInstance; \ + } \ +\ + static inline classname* getInstanceWithoutCreating() throw() \ + { \ + return _singletonInstance; \ + } \ +\ + static void deleteInstance() \ + { \ + if (_singletonInstance != 0) \ + { \ + classname* const old = _singletonInstance; \ + _singletonInstance = 0; \ + delete old; \ + } \ + } \ +\ + void clearSingletonInstance() throw() \ + { \ + if (_singletonInstance == this) \ + _singletonInstance = 0; \ + } - @param results an array to append the results to - @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to - return files, directories, or both. - @param searchRecursively whether to recursively search the subdirectories too - @param wildCardPattern a pattern to match against the filenames - @returns the number of files added to the array - @see File::findChildFiles - */ - int findChildFiles (OwnedArray& results, - const int whatToLookFor, - const bool searchRecursively, - const String& wildCardPattern = JUCE_T("*")) const; +/** + Macro to declare member variables and methods for a singleton class. - /** Finds out whether a file is inside one of the path's directories. + This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking + for recursion or repeated instantiation. It's intended for use as a lightweight + version of a singleton, where you're using it in very straightforward + circumstances and don't need the extra checking. - This will return true if the specified file is a child of one of the - directories specified by this path. Note that this doesn't actually do any - searching or check that the files exist - it just looks at the pathnames - to work out whether the file would be inside a directory. + Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart + to this declaration, as you would with juce_DeclareSingleton_SingleThreaded. - @param fileToCheck the file to look for - @param checkRecursively if true, then this will return true if the file is inside a - subfolder of one of the path's directories (at any depth). If false - it will only return true if the file is actually a direct child - of one of the directories. - @see File::isAChildOf + See the documentation for juce_DeclareSingleton for more information about + how to use it, the only difference being that you have to use + juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. - */ - bool isFileInPath (const File& fileToCheck, - const bool checkRecursively) const; + @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton +*/ +#define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \ +\ + static classname* _singletonInstance; \ +\ + static classname* getInstance() \ + { \ + if (_singletonInstance == 0) \ + _singletonInstance = new classname(); \ +\ + return _singletonInstance; \ + } \ +\ + static inline classname* getInstanceWithoutCreating() throw() \ + { \ + return _singletonInstance; \ + } \ +\ + static void deleteInstance() \ + { \ + if (_singletonInstance != 0) \ + { \ + classname* const old = _singletonInstance; \ + _singletonInstance = 0; \ + delete old; \ + } \ + } \ +\ + void clearSingletonInstance() throw() \ + { \ + if (_singletonInstance == this) \ + _singletonInstance = 0; \ + } - juce_UseDebuggingNewOperator +/** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro. -private: - StringArray directories; + After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal + to the class definition, this macro has to be used somewhere in the cpp file. +*/ +#define juce_ImplementSingleton_SingleThreaded(classname) \ +\ + classname* classname::_singletonInstance = 0; - void init (const String& path); -}; +#endif // __JUCE_SINGLETON_JUCEHEADER__ +/********* End of inlined file: juce_Singleton.h *********/ -#endif // __JUCE_FILESEARCHPATH_JUCEHEADER__ -/********* End of inlined file: juce_FileSearchPath.h *********/ +#endif +#ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ #endif -#ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ +#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ -/********* Start of inlined file: juce_NamedPipe.h *********/ -#ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ -#define __JUCE_NAMEDPIPE_JUCEHEADER__ +/********* Start of inlined file: juce_SystemStats.h *********/ +#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ +#define __JUCE_SYSTEMSTATS_JUCEHEADER__ /** - A cross-process pipe that can have data written to and read from it. - - Two or more processes can use these for inter-process communication. - - @see InterprocessConnection + Contains methods for finding out about the current hardware and OS configuration. */ -class JUCE_API NamedPipe +class JUCE_API SystemStats { public: - /** Creates a NamedPipe. */ - NamedPipe(); - - /** Destructor. */ - ~NamedPipe(); + /** Returns the current version of JUCE, - /** Tries to open a pipe that already exists. + (just in case you didn't already know at compile-time.) - Returns true if it succeeds. + See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros. */ - bool openExisting (const String& pipeName); - - /** Tries to create a new pipe. + static const String getJUCEVersion() throw(); - Returns true if it succeeds. + /** The set of possible results of the getOperatingSystemType() method. */ - bool createNewPipe (const String& pipeName); - - /** Closes the pipe, if it's open. */ - void close(); - - /** True if the pipe is currently open. */ - bool isOpen() const throw(); + enum OperatingSystemType + { + UnknownOS = 0, - /** Returns the last name that was used to try to open this pipe. */ - const String getName() const throw(); + MacOSX = 0x1000, + Linux = 0x2000, - /** Reads data from the pipe. + Win95 = 0x4001, + Win98 = 0x4002, + WinNT351 = 0x4103, + WinNT40 = 0x4104, + Win2000 = 0x4105, + WinXP = 0x4106, + WinVista = 0x4107, + Windows7 = 0x4108, - This will block until another thread has written enough data into the pipe to fill - the number of bytes specified, or until another thread calls the cancelPendingReads() - method. + Windows = 0x4000, /**< To test whether any version of Windows is running, + you can use the expression ((getOperatingSystemType() & Windows) != 0). */ + WindowsNT = 0x0100, /**< To test whether the platform is Windows NT or later (i.e. not Win95 or 98), + you can use the expression ((getOperatingSystemType() & WindowsNT) != 0). */ + }; - If the operation fails, it returns -1, otherwise, it will return the number of - bytes read. + /** Returns the type of operating system we're running on. - If timeOutMilliseconds is less than zero, it will wait indefinitely, otherwise - this is a maximum timeout for reading from the pipe. + @returns one of the values from the OperatingSystemType enum. + @see getOperatingSystemName */ - int read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds = 5000); + static OperatingSystemType getOperatingSystemType() throw(); - /** Writes some data to the pipe. + /** Returns the name of the type of operating system we're running on. - If the operation fails, it returns -1, otherwise, it will return the number of - bytes written. + @returns a string describing the OS type. + @see getOperatingSystemType */ - int write (const void* sourceBuffer, int numBytesToWrite, - int timeOutMilliseconds = 2000); + static const String getOperatingSystemName() throw(); - /** If any threads are currently blocked on a read operation, this tells them to abort. + /** Returns true if the OS is 64-bit, or false for a 32-bit OS. */ - void cancelPendingReads(); + static bool isOperatingSystem64Bit() throw(); - juce_UseDebuggingNewOperator + // CPU and memory information.. -private: - void* internal; - String currentPipeName; + /** Returns the approximate CPU speed. - NamedPipe (const NamedPipe&); - const NamedPipe& operator= (const NamedPipe&); + @returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on + what year you're reading this...) + */ + static int getCpuSpeedInMegaherz() throw(); - bool openInternal (const String& pipeName, const bool createPipe); -}; + /** Returns a string to indicate the CPU vendor. -#endif // __JUCE_NAMEDPIPE_JUCEHEADER__ -/********* End of inlined file: juce_NamedPipe.h *********/ + Might not be known on some systems. + */ + static const String getCpuVendor() throw(); -#endif -#ifndef __JUCE_ZIPFILE_JUCEHEADER__ + /** Checks whether Intel MMX instructions are available. */ + static bool hasMMX() throw(); -/********* Start of inlined file: juce_ZipFile.h *********/ -#ifndef __JUCE_ZIPFILE_JUCEHEADER__ -#define __JUCE_ZIPFILE_JUCEHEADER__ + /** Checks whether Intel SSE instructions are available. */ + static bool hasSSE() throw(); -/********* Start of inlined file: juce_InputSource.h *********/ -#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ -#define __JUCE_INPUTSOURCE_JUCEHEADER__ + /** Checks whether Intel SSE2 instructions are available. */ + static bool hasSSE2() throw(); -/** - A lightweight object that can create a stream to read some kind of resource. + /** Checks whether AMD 3DNOW instructions are available. */ + static bool has3DNow() throw(); - This may be used to refer to a file, or some other kind of source, allowing a - caller to create an input stream that can read from it when required. + /** Returns the number of CPUs. + */ + static int getNumCpus() throw(); - @see FileInputSource -*/ -class JUCE_API InputSource -{ -public: + /** Returns a clock-cycle tick counter, if available. - InputSource() throw() {} + If the machine can do it, this will return a tick-count + where each tick is one cpu clock cycle - used for profiling + code. - /** Destructor. */ - virtual ~InputSource() {} + @returns the tick count, or zero if not available. + */ + static int64 getClockCycleCounter() throw(); - /** Returns a new InputStream to read this item. + /** Finds out how much RAM is in the machine. - @returns an inputstream that the caller will delete, or 0 if - the filename isn't found. + @returns the approximate number of megabytes of memory, or zero if + something goes wrong when finding out. */ - virtual InputStream* createInputStream() = 0; + static int getMemorySizeInMegabytes() throw(); - /** Returns a new InputStream to read an item, relative. + /** Returns the system page-size. - @param relatedItemPath the relative pathname of the resource that is required - @returns an inputstream that the caller will delete, or 0 if - the item isn't found. + This is only used by programmers with beards. */ - virtual InputStream* createInputStreamFor (const String& relatedItemPath) = 0; + static int getPageSize() throw(); - /** Returns a hash code that uniquely represents this item. + /** Returns a list of MAC addresses found on this machine. + + @param addresses an array into which the MAC addresses should be copied + @param maxNum the number of elements in this array + @param littleEndian the endianness of the numbers to return. If this is true, + the least-significant byte of each number is the first byte + of the mac address. If false, the least significant byte is + the last number. Note that the default values of this parameter + are different on Mac/PC to avoid breaking old software that was + written before this parameter was added (when the two systems + defaulted to using different endiannesses). In newer + software you probably want to specify an explicit value + for this. + @returns the number of MAC addresses that were found */ - virtual int64 hashCode() const = 0; + static int getMACAddresses (int64* addresses, int maxNum, +#if JUCE_MAC + const bool littleEndian = true) throw(); +#else + const bool littleEndian = false) throw(); +#endif - juce_UseDebuggingNewOperator + // not-for-public-use platform-specific method gets called at startup to initialise things. + static void initialiseStats() throw(); }; -#endif // __JUCE_INPUTSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_InputSource.h *********/ +#endif // __JUCE_SYSTEMSTATS_JUCEHEADER__ +/********* End of inlined file: juce_SystemStats.h *********/ + +#endif +#ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ + +#endif +#ifndef __JUCE_TIME_JUCEHEADER__ + +#endif +#ifndef __JUCE_UUID_JUCEHEADER__ + +/********* Start of inlined file: juce_Uuid.h *********/ +#ifndef __JUCE_UUID_JUCEHEADER__ +#define __JUCE_UUID_JUCEHEADER__ /** - Decodes a ZIP file from a stream. + A universally unique 128-bit identifier. - This can enumerate the items in a ZIP file and can create suitable stream objects - to read each one. + This class generates very random unique numbers based on the system time + and MAC addresses if any are available. It's extremely unlikely that two identical + UUIDs would ever be created by chance. + + The class includes methods for saving the ID as a string or as raw binary data. */ -class JUCE_API ZipFile +class JUCE_API Uuid { public: - /** Creates a ZipFile for a given stream. - - @param inputStream the stream to read from - @param deleteStreamWhenDestroyed if set to true, the object passed-in - will be deleted when this ZipFile object is deleted - */ - ZipFile (InputStream* const inputStream, - const bool deleteStreamWhenDestroyed) throw(); + /** Creates a new unique ID. */ + Uuid(); - /** Creates a ZipFile based for a file. */ - ZipFile (const File& file); + /** Destructor. */ + ~Uuid() throw(); - /** Creates a ZipFile for an input source. + /** Creates a copy of another UUID. */ + Uuid (const Uuid& other); - The inputSource object will be owned by the zip file, which will delete - it later when not needed. - */ - ZipFile (InputSource* const inputSource); + /** Copies another UUID. */ + Uuid& operator= (const Uuid& other); - /** Destructor. */ - ~ZipFile() throw(); + /** Returns true if the ID is zero. */ + bool isNull() const throw(); - /** - Contains information about one of the entries in a ZipFile. + /** Compares two UUIDs. */ + bool operator== (const Uuid& other) const; - @see ZipFile::getEntry - */ - struct ZipEntry - { - /** The name of the file, which may also include a partial pathname. */ - String filename; + /** Compares two UUIDs. */ + bool operator!= (const Uuid& other) const; - /** The file's original size. */ - unsigned int uncompressedSize; + /** Returns a stringified version of this UUID. - /** The last time the file was modified. */ - Time fileTime; - }; - - /** Returns the number of items in the zip file. */ - int getNumEntries() const throw(); - - /** Returns a structure that describes one of the entries in the zip file. - - This may return zero if the index is out of range. + A Uuid object can later be reconstructed from this string using operator= or + the constructor that takes a string parameter. - @see ZipFile::ZipEntry + @returns a 32 character hex string. */ - const ZipEntry* getEntry (const int index) const throw(); - - /** Returns the index of the first entry with a given filename. + const String toString() const; - This uses a case-sensitive comparison to look for a filename in the - list of entries. It might return -1 if no match is found. + /** Creates an ID from an encoded string version. - @see ZipFile::ZipEntry + @see toString */ - int getIndexOfFileName (const String& fileName) const throw(); - - /** Returns a structure that describes one of the entries in the zip file. - - This uses a case-sensitive comparison to look for a filename in the - list of entries. It might return 0 if no match is found. + Uuid (const String& uuidString); - @see ZipFile::ZipEntry - */ - const ZipEntry* getEntry (const String& fileName) const throw(); + /** Copies from a stringified UUID. - /** Sorts the list of entries, based on the filename. + The string passed in should be one that was created with the toString() method. */ - void sortEntriesByFilename(); - - /** Creates a stream that can read from one of the zip file's entries. + Uuid& operator= (const String& uuidString); - The stream that is returned must be deleted by the caller (and - zero might be returned if a stream can't be opened for some reason). + /** Returns a pointer to the internal binary representation of the ID. - The stream must not be used after the ZipFile object that created - has been deleted. + This is an array of 16 bytes. To reconstruct a Uuid from its data, use + the constructor or operator= method that takes an array of uint8s. */ - InputStream* createStreamForEntry (const int index); - - /** Uncompresses all of the files in the zip file. + const uint8* getRawData() const throw() { return value.asBytes; } - This will expand all the entires into a target directory. The relative - paths of the entries are used. + /** Creates a UUID from a 16-byte array. - @param targetDirectory the root folder to uncompress to - @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones + @see getRawData */ - void uncompressTo (const File& targetDirectory, - const bool shouldOverwriteFiles = true); + Uuid (const uint8* const rawData); + + /** Sets this UUID from 16-bytes of raw data. */ + Uuid& operator= (const uint8* const rawData); juce_UseDebuggingNewOperator private: - VoidArray entries; - friend class ZipInputStream; - CriticalSection lock; - InputStream* inputStream; - InputSource* inputSource; - - bool deleteStreamWhenDestroyed; - int numEntries, centralRecStart; - -#ifdef JUCE_DEBUG - int numOpenStreams; -#endif - - void init(); - int findEndOfZipEntryTable (InputStream* in); + union + { + uint8 asBytes [16]; + int asInt[4]; + int64 asInt64[2]; - ZipFile (const ZipFile&); - const ZipFile& operator= (const ZipFile&); + } value; }; -#endif // __JUCE_ZIPFILE_JUCEHEADER__ -/********* End of inlined file: juce_ZipFile.h *********/ +#endif // __JUCE_UUID_JUCEHEADER__ +/********* End of inlined file: juce_Uuid.h *********/ #endif #ifndef __JUCE_BLOWFISH_JUCEHEADER__ @@ -13724,7 +13379,7 @@ public: private: uint32 p[18]; - uint32* s[4]; + HeapBlock s[4]; uint32 F (uint32 x) const; }; @@ -13954,18131 +13609,17833 @@ protected: /********* End of inlined file: juce_RSAKey.h *********/ #endif -#ifndef __JUCE_SOCKET_JUCEHEADER__ +#ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ -/********* Start of inlined file: juce_Socket.h *********/ -#ifndef __JUCE_SOCKET_JUCEHEADER__ -#define __JUCE_SOCKET_JUCEHEADER__ +/********* Start of inlined file: juce_DirectoryIterator.h *********/ +#ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ +#define __JUCE_DIRECTORYITERATOR_JUCEHEADER__ /** - A wrapper for a streaming (TCP) socket. + Searches through a the files in a directory, returning each file that is found. - This allows low-level use of sockets; for an easier-to-use messaging layer on top of - sockets, you could also try the InterprocessConnection class. + A DirectoryIterator will search through a directory and its subdirectories using + a wildcard filepattern match. - @see DatagramSocket, InterprocessConnection, InterprocessConnectionServer + If you may be finding a large number of files, this is better than + using File::findChildFiles() because it doesn't block while it finds them + all, and this is more memory-efficient. + + It can also guess how far it's got using a wildly inaccurate algorithm. */ -class JUCE_API StreamingSocket +class JUCE_API DirectoryIterator { public: - /** Creates an uninitialised socket. + /** Creates a DirectoryIterator for a given directory. - To connect it, use the connect() method, after which you can read() or write() - to it. + After creating one of these, call its next() method to get the + first file - e.g. @code - To wait for other sockets to connect to this one, the createListener() method - enters "listener" mode, and can be used to spawn new sockets for each connection - that comes along. + DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose"); + + while (iter.next()) + { + File theFileItFound (iter.getFile()); + + ... etc + } + @endcode + + @param directory the directory to search in + @param isRecursive whether all the subdirectories should also be searched + @param wildCard the file pattern to match + @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying + whether to look for files, directories, or both. */ - StreamingSocket(); + DirectoryIterator (const File& directory, + bool isRecursive, + const String& wildCard = JUCE_T("*"), + const int whatToLookFor = File::findFiles) throw(); /** Destructor. */ - ~StreamingSocket(); + ~DirectoryIterator() throw(); - /** Binds the socket to the specified local port. + /** Call this to move the iterator along to the next file. - @returns true on success; false may indicate that another socket is already bound - on the same port + @returns true if a file was found (you can then use getFile() to see what it was) - or + false if there are no more matching files. */ - bool bindToPort (const int localPortNumber); + bool next() throw(); - /** Tries to connect the socket to hostname:port. + /** Returns the file that the iterator is currently pointing at. - If timeOutMillisecs is 0, then this method will block until the operating system - rejects the connection (which could take a long time). + The result of this call is only valid after a call to next() has returned true. + */ + const File getFile() const throw(); - @returns true if it succeeds. - @see isConnected + /** Returns a guess of how far through the search the iterator has got. + + @returns a value 0.0 to 1.0 to show the progress, although this won't be + very accurate. */ - bool connect (const String& remoteHostname, - const int remotePortNumber, - const int timeOutMillisecs = 3000); + float getEstimatedProgress() const throw(); - /** True if the socket is currently connected. */ - bool isConnected() const throw() { return connected; } + juce_UseDebuggingNewOperator - /** Closes the connection. */ - void close(); +private: + OwnedArray filesFound; + OwnedArray dirsFound; + String wildCard; + int index; + const int whatToLookFor; + DirectoryIterator* subIterator; - /** Returns the name of the currently connected host. */ - const String& getHostName() const throw() { return hostName; } + DirectoryIterator (const DirectoryIterator&); + const DirectoryIterator& operator= (const DirectoryIterator&); +}; - /** Returns the port number that's currently open. */ - int getPort() const throw() { return portNumber; } +#endif // __JUCE_DIRECTORYITERATOR_JUCEHEADER__ +/********* End of inlined file: juce_DirectoryIterator.h *********/ - /** True if the socket is connected to this machine rather than over the network. */ - bool isLocal() const throw(); +#endif +#ifndef __JUCE_FILE_JUCEHEADER__ - /** Waits until the socket is ready for reading or writing. +#endif +#ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ - If readyForReading is true, it will wait until the socket is ready for - reading; if false, it will wait until it's ready for writing. +/********* Start of inlined file: juce_FileInputStream.h *********/ +#ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ +#define __JUCE_FILEINPUTSTREAM_JUCEHEADER__ - If the timeout is < 0, it will wait forever, or else will give up after - the specified time. +/** + An input stream that reads from a local file. - If the socket is ready on return, this returns 1. If it times-out before - the socket becomes ready, it returns 0. If an error occurs, it returns -1. + @see InputStream, FileOutputStream, File::createInputStream +*/ +class JUCE_API FileInputStream : public InputStream +{ +public: + + /** Creates a FileInputStream. + + @param fileToRead the file to read from - if the file can't be accessed for some + reason, then the stream will just contain no data */ - int waitUntilReady (const bool readyForReading, - const int timeoutMsecs) const; + FileInputStream (const File& fileToRead); - /** Reads bytes from the socket. + /** Destructor. */ + ~FileInputStream(); - If blockUntilSpecifiedAmountHasArrived is true, the method will block until - maxBytesToRead bytes have been read, (or until an error occurs). If this - flag is false, the method will return as much data as is currently available - without blocking. + const File& getFile() const throw() { return file; } - @returns the number of bytes read, or -1 if there was an error. - @see waitUntilReady - */ - int read (void* destBuffer, const int maxBytesToRead, - const bool blockUntilSpecifiedAmountHasArrived); + int64 getTotalLength(); + int read (void* destBuffer, int maxBytesToRead); + bool isExhausted(); + int64 getPosition(); + bool setPosition (int64 pos); - /** Writes bytes to the socket from a buffer. + juce_UseDebuggingNewOperator - Note that this method will block unless you have checked the socket is ready - for writing before calling it (see the waitUntilReady() method). +private: + File file; + void* fileHandle; + int64 currentPosition, totalSize; + bool needToSeek; - @returns the number of bytes written, or -1 if there was an error. - */ - int write (const void* sourceBuffer, const int numBytesToWrite); + FileInputStream (const FileInputStream&); + const FileInputStream& operator= (const FileInputStream&); +}; - /** Puts this socket into "listener" mode. +#endif // __JUCE_FILEINPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_FileInputStream.h *********/ - When in this mode, your thread can call waitForNextConnection() repeatedly, - which will spawn new sockets for each new connection, so that these can - be handled in parallel by other threads. +#endif +#ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ - @param portNumber the port number to listen on - @param localHostName the interface address to listen on - pass an empty - string to listen on all addresses - @returns true if it manages to open the socket successfully. +/********* Start of inlined file: juce_FileOutputStream.h *********/ +#ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ +#define __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ - @see waitForNextConnection - */ - bool createListener (const int portNumber, const String& localHostName = String::empty); +/** + An output stream that writes into a local file. - /** When in "listener" mode, this waits for a connection and spawns it as a new - socket. + @see OutputStream, FileInputStream, File::createOutputStream +*/ +class JUCE_API FileOutputStream : public OutputStream +{ +public: - The object that gets returned will be owned by the caller. + /** Creates a FileOutputStream. - This method can only be called after using createListener(). + If the file doesn't exist, it will first be created. If the file can't be + created or opened, the failedToOpen() method will return + true. - @see createListener + If the file already exists when opened, the stream's write-postion will + be set to the end of the file. To overwrite an existing file, + use File::deleteFile() before opening the stream, or use setPosition(0) + after it's opened (although this won't truncate the file). + + It's better to use File::createOutputStream() to create one of these, rather + than using the class directly. */ - StreamingSocket* waitForNextConnection() const; + FileOutputStream (const File& fileToWriteTo, + const int bufferSizeToUse = 16384); + + /** Destructor. */ + ~FileOutputStream(); + + /** Returns the file that this stream is writing to. + */ + const File& getFile() const throw() { return file; } + + /** Returns true if the stream couldn't be opened for some reason. + */ + bool failedToOpen() const throw() { return fileHandle == 0; } + + void flush(); + int64 getPosition(); + bool setPosition (int64 pos); + bool write (const void* data, int numBytes); juce_UseDebuggingNewOperator private: - String hostName; - int volatile portNumber, handle; - bool connected, isListener; - - StreamingSocket (const String& hostname, const int portNumber, const int handle); - StreamingSocket (const StreamingSocket&); - const StreamingSocket& operator= (const StreamingSocket&); + File file; + void* fileHandle; + int64 currentPosition; + int bufferSize, bytesInBuffer; + HeapBlock buffer; }; -/** - A wrapper for a datagram (UDP) socket. +#endif // __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_FileOutputStream.h *********/ - This allows low-level use of sockets; for an easier-to-use messaging layer on top of - sockets, you could also try the InterprocessConnection class. +#endif +#ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ - @see StreamingSocket, InterprocessConnection, InterprocessConnectionServer +/********* Start of inlined file: juce_FileSearchPath.h *********/ +#ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ +#define __JUCE_FILESEARCHPATH_JUCEHEADER__ + +/** + Encapsulates a set of folders that make up a search path. + + @see File */ -class JUCE_API DatagramSocket +class JUCE_API FileSearchPath { public: - /** - Creates an (uninitialised) datagram socket. - - The localPortNumber is the port on which to bind this socket. If this value is 0, - the port number is assigned by the operating system. + /** Creates an empty search path. */ + FileSearchPath(); - To use the socket for sending, call the connect() method. This will not immediately - make a connection, but will save the destination you've provided. After this, you can - call read() or write(). + /** Creates a search path from a string of pathnames. - If enableBroadcasting is true, the socket will be allowed to send broadcast messages - (may require extra privileges on linux) + The path can be semicolon- or comma-separated, e.g. + "/foo/bar;/foo/moose;/fish/moose" - To wait for other sockets to connect to this one, call waitForNextConnection(). + The separate folders are tokenised and added to the search path. */ - DatagramSocket (const int localPortNumber, - const bool enableBroadcasting = false); + FileSearchPath (const String& path); + + /** Creates a copy of another search path. */ + FileSearchPath (const FileSearchPath& other); /** Destructor. */ - ~DatagramSocket(); + ~FileSearchPath(); - /** Binds the socket to the specified local port. + /** Uses a string containing a list of pathnames to re-initialise this list. - @returns true on success; false may indicate that another socket is already bound - on the same port + This search path is cleared and the semicolon- or comma-separated folders + in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose" */ - bool bindToPort (const int localPortNumber); - - /** Tries to connect the socket to hostname:port. + const FileSearchPath& operator= (const String& path); - If timeOutMillisecs is 0, then this method will block until the operating system - rejects the connection (which could take a long time). + /** Returns the number of folders in this search path. - @returns true if it succeeds. - @see isConnected + @see operator[] */ - bool connect (const String& remoteHostname, - const int remotePortNumber, - const int timeOutMillisecs = 3000); + int getNumPaths() const; - /** True if the socket is currently connected. */ - bool isConnected() const throw() { return connected; } + /** Returns one of the folders in this search path. - /** Closes the connection. */ - void close(); + The file returned isn't guaranteed to actually be a valid directory. - /** Returns the name of the currently connected host. */ - const String& getHostName() const throw() { return hostName; } + @see getNumPaths + */ + const File operator[] (const int index) const; - /** Returns the port number that's currently open. */ - int getPort() const throw() { return portNumber; } + /** Returns the search path as a semicolon-separated list of directories. */ + const String toString() const; - /** True if the socket is connected to this machine rather than over the network. */ - bool isLocal() const throw(); + /** Adds a new directory to the search path. - /** Waits until the socket is ready for reading or writing. + The new directory is added to the end of the list if the insertIndex parameter is + less than zero, otherwise it is inserted at the given index. + */ + void add (const File& directoryToAdd, + const int insertIndex = -1); - If readyForReading is true, it will wait until the socket is ready for - reading; if false, it will wait until it's ready for writing. + /** Adds a new directory to the search path if it's not already in there. */ + void addIfNotAlreadyThere (const File& directoryToAdd); - If the timeout is < 0, it will wait forever, or else will give up after - the specified time. + /** Removes a directory from the search path. */ + void remove (const int indexToRemove); - If the socket is ready on return, this returns 1. If it times-out before - the socket becomes ready, it returns 0. If an error occurs, it returns -1. + /** Merges another search path into this one. + + This will remove any duplicate directories. */ - int waitUntilReady (const bool readyForReading, - const int timeoutMsecs) const; + void addPath (const FileSearchPath& other); - /** Reads bytes from the socket. + /** Removes any directories that are actually subdirectories of one of the other directories in the search path. - If blockUntilSpecifiedAmountHasArrived is true, the method will block until - maxBytesToRead bytes have been read, (or until an error occurs). If this - flag is false, the method will return as much data as is currently available - without blocking. + If the search is intended to be recursive, there's no point having nested folders in the search + path, because they'll just get searched twice and you'll get duplicate results. - @returns the number of bytes read, or -1 if there was an error. - @see waitUntilReady + e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc" */ - int read (void* destBuffer, const int maxBytesToRead, - const bool blockUntilSpecifiedAmountHasArrived); + void removeRedundantPaths(); - /** Writes bytes to the socket from a buffer. + /** Removes any directories that don't actually exist. */ + void removeNonExistentPaths(); - Note that this method will block unless you have checked the socket is ready - for writing before calling it (see the waitUntilReady() method). + /** Searches the path for a wildcard. - @returns the number of bytes written, or -1 if there was an error. + This will search all the directories in the search path in order, adding any + matching files to the results array. + + @param results an array to append the results to + @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to + return files, directories, or both. + @param searchRecursively whether to recursively search the subdirectories too + @param wildCardPattern a pattern to match against the filenames + @returns the number of files added to the array + @see File::findChildFiles */ - int write (const void* sourceBuffer, const int numBytesToWrite); + int findChildFiles (OwnedArray& results, + const int whatToLookFor, + const bool searchRecursively, + const String& wildCardPattern = JUCE_T("*")) const; - /** This waits for incoming data to be sent, and returns a socket that can be used - to read it. + /** Finds out whether a file is inside one of the path's directories. + + This will return true if the specified file is a child of one of the + directories specified by this path. Note that this doesn't actually do any + searching or check that the files exist - it just looks at the pathnames + to work out whether the file would be inside a directory. + + @param fileToCheck the file to look for + @param checkRecursively if true, then this will return true if the file is inside a + subfolder of one of the path's directories (at any depth). If false + it will only return true if the file is actually a direct child + of one of the directories. + @see File::isAChildOf - The object that gets returned is owned by the caller, and can't be used for - sending, but can be used to read the data. */ - DatagramSocket* waitForNextConnection() const; + bool isFileInPath (const File& fileToCheck, + const bool checkRecursively) const; juce_UseDebuggingNewOperator private: - String hostName; - int volatile portNumber, handle; - bool connected, allowBroadcast; - void* serverAddress; + StringArray directories; - DatagramSocket (const String& hostname, const int portNumber, const int handle, const int localPortNumber); - DatagramSocket (const DatagramSocket&); - const DatagramSocket& operator= (const DatagramSocket&); + void init (const String& path); }; -#endif // __JUCE_SOCKET_JUCEHEADER__ -/********* End of inlined file: juce_Socket.h *********/ +#endif // __JUCE_FILESEARCHPATH_JUCEHEADER__ +/********* End of inlined file: juce_FileSearchPath.h *********/ #endif -#ifndef __JUCE_URL_JUCEHEADER__ +#ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ -/********* Start of inlined file: juce_URL.h *********/ -#ifndef __JUCE_URL_JUCEHEADER__ -#define __JUCE_URL_JUCEHEADER__ +/********* Start of inlined file: juce_NamedPipe.h *********/ +#ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ +#define __JUCE_NAMEDPIPE_JUCEHEADER__ /** - Represents a URL and has a bunch of useful functions to manipulate it. + A cross-process pipe that can have data written to and read from it. - This class can be used to launch URLs in browsers, and also to create - InputStreams that can read from remote http or ftp sources. + Two or more processes can use these for inter-process communication. + + @see InterprocessConnection */ -class JUCE_API URL +class JUCE_API NamedPipe { public: - /** Creates an empty URL. */ - URL() throw(); - - /** Creates a URL from a string. */ - URL (const String& url); - - /** Creates a copy of another URL. */ - URL (const URL& other); + /** Creates a NamedPipe. */ + NamedPipe(); /** Destructor. */ - ~URL() throw(); - - /** Copies this URL from another one. */ - const URL& operator= (const URL& other); + ~NamedPipe(); - /** Returns a string version of the URL. + /** Tries to open a pipe that already exists. - If includeGetParameters is true and any parameters have been set with the - withParameter() method, then the string will have these appended on the - end and url-encoded. + Returns true if it succeeds. */ - const String toString (const bool includeGetParameters) const; - - /** True if it seems to be valid. */ - bool isWellFormed() const; + bool openExisting (const String& pipeName); - /** Returns just the domain part of the URL. + /** Tries to create a new pipe. - E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". + Returns true if it succeeds. */ - const String getDomain() const; + bool createNewPipe (const String& pipeName); - /** Returns the path part of the URL. + /** Closes the pipe, if it's open. */ + void close(); - E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". - */ - const String getSubPath() const; + /** True if the pipe is currently open. */ + bool isOpen() const throw(); - /** Returns the scheme of the URL. + /** Returns the last name that was used to try to open this pipe. */ + const String getName() const throw(); - E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't - include the colon). - */ - const String getScheme() const; + /** Reads data from the pipe. - /** Returns a new version of this URL that uses a different sub-path. + This will block until another thread has written enough data into the pipe to fill + the number of bytes specified, or until another thread calls the cancelPendingReads() + method. - E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with - "bar", it'll return "http://www.xyz.com/bar?x=1". + If the operation fails, it returns -1, otherwise, it will return the number of + bytes read. + + If timeOutMilliseconds is less than zero, it will wait indefinitely, otherwise + this is a maximum timeout for reading from the pipe. */ - const URL withNewSubPath (const String& newPath) const; + int read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds = 5000); - /** Returns a copy of this URL, with a GET parameter added to the end. + /** Writes some data to the pipe. - Any control characters in the value will be encoded. + If the operation fails, it returns -1, otherwise, it will return the number of + bytes written. + */ + int write (const void* sourceBuffer, int numBytesToWrite, + int timeOutMilliseconds = 2000); - e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com" - would produce a new url whose toString(true) method would return - "www.fish.com?amount=some+fish". + /** If any threads are currently blocked on a read operation, this tells them to abort. */ - const URL withParameter (const String& parameterName, - const String& parameterValue) const; + void cancelPendingReads(); - /** Returns a copy of this URl, with a file-upload type parameter added to it. + juce_UseDebuggingNewOperator - When performing a POST where one of your parameters is a binary file, this - lets you specify the file. +private: + void* internal; + String currentPipeName; - Note that the filename is stored, but the file itself won't actually be read - until this URL is later used to create a network input stream. - */ - const URL withFileToUpload (const String& parameterName, - const File& fileToUpload, - const String& mimeType) const; + NamedPipe (const NamedPipe&); + const NamedPipe& operator= (const NamedPipe&); - /** Returns a set of all the parameters encoded into the url. + bool openInternal (const String& pipeName, const bool createPipe); +}; - E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would - contain two pairs: "type" => "haddock" and "amount" => "some fish". +#endif // __JUCE_NAMEDPIPE_JUCEHEADER__ +/********* End of inlined file: juce_NamedPipe.h *********/ - The values returned will have been cleaned up to remove any escape characters. +#endif +#ifndef __JUCE_ZIPFILE_JUCEHEADER__ - @see getNamedParameter, withParameter - */ - const StringPairArray& getParameters() const throw(); +/********* Start of inlined file: juce_ZipFile.h *********/ +#ifndef __JUCE_ZIPFILE_JUCEHEADER__ +#define __JUCE_ZIPFILE_JUCEHEADER__ - /** Returns the set of files that should be uploaded as part of a POST operation. +/********* Start of inlined file: juce_InputSource.h *********/ +#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ +#define __JUCE_INPUTSOURCE_JUCEHEADER__ - This is the set of files that were added to the URL with the withFileToUpload() - method. - */ - const StringPairArray& getFilesToUpload() const throw(); +/** + A lightweight object that can create a stream to read some kind of resource. - /** Returns the set of mime types associated with each of the upload files. - */ - const StringPairArray& getMimeTypesOfUploadFiles() const throw(); + This may be used to refer to a file, or some other kind of source, allowing a + caller to create an input stream that can read from it when required. - /** Returns a copy of this URL, with a block of data to send as the POST data. + @see FileInputSource +*/ +class JUCE_API InputSource +{ +public: - If you're setting the POST data, be careful not to have any parameters set - as well, otherwise it'll all get thrown in together, and might not have the - desired effect. + InputSource() throw() {} - If the URL already contains some POST data, this will replace it, rather - than being appended to it. + /** Destructor. */ + virtual ~InputSource() {} - This data will only be used if you specify a post operation when you call - createInputStream(). - */ - const URL withPOSTData (const String& postData) const; + /** Returns a new InputStream to read this item. - /** Returns the data that was set using withPOSTData(). + @returns an inputstream that the caller will delete, or 0 if + the filename isn't found. */ - const String getPostData() const throw() { return postData; } + virtual InputStream* createInputStream() = 0; - /** Tries to launch the system's default browser to open the URL. + /** Returns a new InputStream to read an item, relative. - Returns true if this seems to have worked. + @param relatedItemPath the relative pathname of the resource that is required + @returns an inputstream that the caller will delete, or 0 if + the item isn't found. */ - bool launchInDefaultBrowser() const; - - /** Takes a guess as to whether a string might be a valid website address. + virtual InputStream* createInputStreamFor (const String& relatedItemPath) = 0; - This isn't foolproof! + /** Returns a hash code that uniquely represents this item. */ - static bool isProbablyAWebsiteURL (const String& possibleURL); + virtual int64 hashCode() const = 0; - /** Takes a guess as to whether a string might be a valid email address. + juce_UseDebuggingNewOperator +}; - This isn't foolproof! - */ - static bool isProbablyAnEmailAddress (const String& possibleEmailAddress); +#endif // __JUCE_INPUTSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_InputSource.h *********/ - /** This callback function can be used by the createInputStream() method. +/** + Decodes a ZIP file from a stream. - It allows your app to receive progress updates during a lengthy POST operation. If you - want to continue the operation, this should return true, or false to abort. - */ - typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes); + This can enumerate the items in a ZIP file and can create suitable stream objects + to read each one. +*/ +class JUCE_API ZipFile +{ +public: - /** Attempts to open a stream that can read from this URL. + /** Creates a ZipFile for a given stream. - @param usePostCommand if true, it will try to do use a http 'POST' to pass - the paramters, otherwise it'll encode them into the - URL and do a 'GET'. - @param progressCallback if this is non-zero, it lets you supply a callback function - to keep track of the operation's progress. This can be useful - for lengthy POST operations, so that you can provide user feedback. - @param progressCallbackContext if a callback is specified, this value will be passed to - the function - @param extraHeaders if not empty, this string is appended onto the headers that - are used for the request. It must therefore be a valid set of HTML - header directives, separated by newlines. - @param connectionTimeOutMs if 0, this will use whatever default setting the OS chooses. If - a negative number, it will be infinite. Otherwise it specifies a - time in milliseconds. + @param inputStream the stream to read from + @param deleteStreamWhenDestroyed if set to true, the object passed-in + will be deleted when this ZipFile object is deleted */ - InputStream* createInputStream (const bool usePostCommand, - OpenStreamProgressCallback* const progressCallback = 0, - void* const progressCallbackContext = 0, - const String& extraHeaders = String::empty, - const int connectionTimeOutMs = 0) const; + ZipFile (InputStream* const inputStream, + const bool deleteStreamWhenDestroyed) throw(); - /** Tries to download the entire contents of this URL into a binary data block. + /** Creates a ZipFile based for a file. */ + ZipFile (const File& file); - If it succeeds, this will return true and append the data it read onto the end - of the memory block. + /** Creates a ZipFile for an input source. - @param destData the memory block to append the new data to - @param usePostCommand whether to use a POST command to get the data (uses - a GET command if this is false) - @see readEntireTextStream, readEntireXmlStream + The inputSource object will be owned by the zip file, which will delete + it later when not needed. */ - bool readEntireBinaryStream (MemoryBlock& destData, - const bool usePostCommand = false) const; + ZipFile (InputSource* const inputSource); - /** Tries to download the entire contents of this URL as a string. + /** Destructor. */ + ~ZipFile() throw(); - If it fails, this will return an empty string, otherwise it will return the - contents of the downloaded file. If you need to distinguish between a read - operation that fails and one that returns an empty string, you'll need to use - a different method, such as readEntireBinaryStream(). + /** + Contains information about one of the entries in a ZipFile. - @param usePostCommand whether to use a POST command to get the data (uses - a GET command if this is false) - @see readEntireBinaryStream, readEntireXmlStream + @see ZipFile::getEntry */ - const String readEntireTextStream (const bool usePostCommand = false) const; - - /** Tries to download the entire contents of this URL and parse it as XML. + struct ZipEntry + { + /** The name of the file, which may also include a partial pathname. */ + String filename; - If it fails, or if the text that it reads can't be parsed as XML, this will - return 0. + /** The file's original size. */ + unsigned int uncompressedSize; - When it returns a valid XmlElement object, the caller is responsibile for deleting - this object when no longer needed. + /** The last time the file was modified. */ + Time fileTime; + }; - @param usePostCommand whether to use a POST command to get the data (uses - a GET command if this is false) + /** Returns the number of items in the zip file. */ + int getNumEntries() const throw(); - @see readEntireBinaryStream, readEntireTextStream - */ - XmlElement* readEntireXmlStream (const bool usePostCommand = false) const; + /** Returns a structure that describes one of the entries in the zip file. - /** Adds escape sequences to a string to encode any characters that aren't - legal in a URL. + This may return zero if the index is out of range. - E.g. any spaces will be replaced with "%20". + @see ZipFile::ZipEntry + */ + const ZipEntry* getEntry (const int index) const throw(); - This is the opposite of removeEscapeChars(). + /** Returns the index of the first entry with a given filename. - If isParameter is true, it means that the string is going to be used - as a parameter, so it also encodes '$' and ',' (which would otherwise - be legal in a URL. + This uses a case-sensitive comparison to look for a filename in the + list of entries. It might return -1 if no match is found. - @see removeEscapeChars + @see ZipFile::ZipEntry */ - static const String addEscapeChars (const String& stringToAddEscapeCharsTo, - const bool isParameter); - - /** Replaces any escape character sequences in a string with their original - character codes. + int getIndexOfFileName (const String& fileName) const throw(); - E.g. any instances of "%20" will be replaced by a space. + /** Returns a structure that describes one of the entries in the zip file. - This is the opposite of addEscapeChars(). + This uses a case-sensitive comparison to look for a filename in the + list of entries. It might return 0 if no match is found. - @see addEscapeChars + @see ZipFile::ZipEntry */ - static const String removeEscapeChars (const String& stringToRemoveEscapeCharsFrom); - - juce_UseDebuggingNewOperator - -private: - String url, postData; - StringPairArray parameters, filesToUpload, mimeTypes; -}; + const ZipEntry* getEntry (const String& fileName) const throw(); -#endif // __JUCE_URL_JUCEHEADER__ -/********* End of inlined file: juce_URL.h *********/ + /** Sorts the list of entries, based on the filename. + */ + void sortEntriesByFilename(); -#endif -#ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ + /** Creates a stream that can read from one of the zip file's entries. -/********* Start of inlined file: juce_BufferedInputStream.h *********/ -#ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ -#define __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ + The stream that is returned must be deleted by the caller (and + zero might be returned if a stream can't be opened for some reason). -/** Wraps another input stream, and reads from it using an intermediate buffer + The stream must not be used after the ZipFile object that created + has been deleted. + */ + InputStream* createStreamForEntry (const int index); - If you're using an input stream such as a file input stream, and making lots of - small read accesses to it, it's probably sensible to wrap it in one of these, - so that the source stream gets accessed in larger chunk sizes, meaning less - work for the underlying stream. -*/ -class JUCE_API BufferedInputStream : public InputStream -{ -public: + /** Uncompresses all of the files in the zip file. - /** Creates a BufferedInputStream from an input source. + This will expand all the entires into a target directory. The relative + paths of the entries are used. - @param sourceStream the source stream to read from - @param bufferSize the size of reservoir to use to buffer the source - @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be - deleted by this object when it is itself deleted. + @param targetDirectory the root folder to uncompress to + @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones */ - BufferedInputStream (InputStream* const sourceStream, - const int bufferSize, - const bool deleteSourceWhenDestroyed) throw(); + void uncompressTo (const File& targetDirectory, + const bool shouldOverwriteFiles = true); - /** Destructor. + juce_UseDebuggingNewOperator - This may also delete the source stream, if that option was chosen when the - buffered stream was created. - */ - ~BufferedInputStream() throw(); +private: + VoidArray entries; + friend class ZipInputStream; + CriticalSection lock; + InputStream* inputStream; + InputSource* inputSource; - int64 getTotalLength(); - int64 getPosition(); - bool setPosition (int64 newPosition); - int read (void* destBuffer, int maxBytesToRead); - const String readString(); - bool isExhausted(); + bool deleteStreamWhenDestroyed; + int numEntries, centralRecStart; - juce_UseDebuggingNewOperator +#ifdef JUCE_DEBUG + int numOpenStreams; +#endif -private: - InputStream* const source; - const bool deleteSourceWhenDestroyed; - int bufferSize; - int64 position, lastReadPos, bufferStart, bufferOverlap; - char* buffer; - void ensureBuffered(); + void init(); + int findEndOfZipEntryTable (InputStream* in); - BufferedInputStream (const BufferedInputStream&); - const BufferedInputStream& operator= (const BufferedInputStream&); + ZipFile (const ZipFile&); + const ZipFile& operator= (const ZipFile&); }; -#endif // __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_BufferedInputStream.h *********/ +#endif // __JUCE_ZIPFILE_JUCEHEADER__ +/********* End of inlined file: juce_ZipFile.h *********/ #endif -#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ +#ifndef __JUCE_SOCKET_JUCEHEADER__ -/********* Start of inlined file: juce_FileInputSource.h *********/ -#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ -#define __JUCE_FILEINPUTSOURCE_JUCEHEADER__ +/********* Start of inlined file: juce_Socket.h *********/ +#ifndef __JUCE_SOCKET_JUCEHEADER__ +#define __JUCE_SOCKET_JUCEHEADER__ /** - A type of InputSource that represents a normal file. + A wrapper for a streaming (TCP) socket. - @see InputSource + This allows low-level use of sockets; for an easier-to-use messaging layer on top of + sockets, you could also try the InterprocessConnection class. + + @see DatagramSocket, InterprocessConnection, InterprocessConnectionServer */ -class JUCE_API FileInputSource : public InputSource +class JUCE_API StreamingSocket { public: - FileInputSource (const File& file) throw(); - ~FileInputSource(); - - InputStream* createInputStream(); - InputStream* createInputStreamFor (const String& relatedItemPath); - int64 hashCode() const; - - juce_UseDebuggingNewOperator - -private: - const File file; + /** Creates an uninitialised socket. - FileInputSource (const FileInputSource&); - const FileInputSource& operator= (const FileInputSource&); -}; + To connect it, use the connect() method, after which you can read() or write() + to it. -#endif // __JUCE_FILEINPUTSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_FileInputSource.h *********/ + To wait for other sockets to connect to this one, the createListener() method + enters "listener" mode, and can be used to spawn new sockets for each connection + that comes along. + */ + StreamingSocket(); -#endif -#ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ + /** Destructor. */ + ~StreamingSocket(); -/********* Start of inlined file: juce_GZIPCompressorOutputStream.h *********/ -#ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ -#define __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ + /** Binds the socket to the specified local port. -/** - A stream which uses zlib to compress the data written into it. + @returns true on success; false may indicate that another socket is already bound + on the same port + */ + bool bindToPort (const int localPortNumber); - @see GZIPDecompressorInputStream -*/ -class JUCE_API GZIPCompressorOutputStream : public OutputStream -{ -public: + /** Tries to connect the socket to hostname:port. - /** Creates a compression stream. + If timeOutMillisecs is 0, then this method will block until the operating system + rejects the connection (which could take a long time). - @param destStream the stream into which the compressed data should - be written - @param compressionLevel how much to compress the data, between 1 and 9, where - 1 is the fastest/lowest compression, and 9 is the - slowest/highest compression. Any value outside this range - indicates that a default compression level should be used. - @param deleteDestStreamWhenDestroyed whether or not to delete the destStream object when - this stream is destroyed - @param noWrap this is used internally by the ZipFile class - and should be ignored by user applications + @returns true if it succeeds. + @see isConnected */ - GZIPCompressorOutputStream (OutputStream* const destStream, - int compressionLevel = 0, - const bool deleteDestStreamWhenDestroyed = false, - const bool noWrap = false); + bool connect (const String& remoteHostname, + const int remotePortNumber, + const int timeOutMillisecs = 3000); - /** Destructor. */ - ~GZIPCompressorOutputStream(); + /** True if the socket is currently connected. */ + bool isConnected() const throw() { return connected; } - void flush(); - int64 getPosition(); - bool setPosition (int64 newPosition); - bool write (const void* destBuffer, int howMany); + /** Closes the connection. */ + void close(); - juce_UseDebuggingNewOperator + /** Returns the name of the currently connected host. */ + const String& getHostName() const throw() { return hostName; } -private: - OutputStream* const destStream; - const bool deleteDestStream; - uint8* buffer; - void* helper; - bool doNextBlock(); + /** Returns the port number that's currently open. */ + int getPort() const throw() { return portNumber; } - GZIPCompressorOutputStream (const GZIPCompressorOutputStream&); - const GZIPCompressorOutputStream& operator= (const GZIPCompressorOutputStream&); -}; + /** True if the socket is connected to this machine rather than over the network. */ + bool isLocal() const throw(); -#endif // __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_GZIPCompressorOutputStream.h *********/ + /** Waits until the socket is ready for reading or writing. -#endif -#ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ + If readyForReading is true, it will wait until the socket is ready for + reading; if false, it will wait until it's ready for writing. -/********* Start of inlined file: juce_GZIPDecompressorInputStream.h *********/ -#ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ -#define __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ + If the timeout is < 0, it will wait forever, or else will give up after + the specified time. -/** - This stream will decompress a source-stream using zlib. + If the socket is ready on return, this returns 1. If it times-out before + the socket becomes ready, it returns 0. If an error occurs, it returns -1. + */ + int waitUntilReady (const bool readyForReading, + const int timeoutMsecs) const; - Tip: if you're reading lots of small items from one of these streams, you - can increase the performance enormously by passing it through a - BufferedInputStream, so that it has to read larger blocks less often. + /** Reads bytes from the socket. - @see GZIPCompressorOutputStream -*/ -class JUCE_API GZIPDecompressorInputStream : public InputStream -{ -public: - - /** Creates a decompressor stream. + If blockUntilSpecifiedAmountHasArrived is true, the method will block until + maxBytesToRead bytes have been read, (or until an error occurs). If this + flag is false, the method will return as much data as is currently available + without blocking. - @param sourceStream the stream to read from - @param deleteSourceWhenDestroyed whether or not to delete the source stream - when this object is destroyed - @param noWrap this is used internally by the ZipFile class - and should be ignored by user applications - @param uncompressedStreamLength if the creator knows the length that the - uncompressed stream will be, then it can supply this - value, which will be returned by getTotalLength() + @returns the number of bytes read, or -1 if there was an error. + @see waitUntilReady */ - GZIPDecompressorInputStream (InputStream* const sourceStream, - const bool deleteSourceWhenDestroyed, - const bool noWrap = false, - const int64 uncompressedStreamLength = -1); - - /** Destructor. */ - ~GZIPDecompressorInputStream(); - - int64 getPosition(); - bool setPosition (int64 pos); - int64 getTotalLength(); - bool isExhausted(); - int read (void* destBuffer, int maxBytesToRead); - - juce_UseDebuggingNewOperator + int read (void* destBuffer, const int maxBytesToRead, + const bool blockUntilSpecifiedAmountHasArrived); -private: - InputStream* const sourceStream; - const int64 uncompressedStreamLength; - const bool deleteSourceWhenDestroyed, noWrap; - bool isEof; - int activeBufferSize; - int64 originalSourcePos, currentPos; - uint8* buffer; - void* helper; + /** Writes bytes to the socket from a buffer. - GZIPDecompressorInputStream (const GZIPDecompressorInputStream&); - const GZIPDecompressorInputStream& operator= (const GZIPDecompressorInputStream&); -}; + Note that this method will block unless you have checked the socket is ready + for writing before calling it (see the waitUntilReady() method). -#endif // __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_GZIPDecompressorInputStream.h *********/ + @returns the number of bytes written, or -1 if there was an error. + */ + int write (const void* sourceBuffer, const int numBytesToWrite); -#endif -#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ + /** Puts this socket into "listener" mode. -#endif -#ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ + When in this mode, your thread can call waitForNextConnection() repeatedly, + which will spawn new sockets for each new connection, so that these can + be handled in parallel by other threads. -#endif -#ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ + @param portNumber the port number to listen on + @param localHostName the interface address to listen on - pass an empty + string to listen on all addresses + @returns true if it manages to open the socket successfully. -/********* Start of inlined file: juce_MemoryInputStream.h *********/ -#ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ -#define __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ + @see waitForNextConnection + */ + bool createListener (const int portNumber, const String& localHostName = String::empty); -/** - Allows a block of data and to be accessed as a stream. + /** When in "listener" mode, this waits for a connection and spawns it as a new + socket. - This can either be used to refer to a shared block of memory, or can make its - own internal copy of the data when the MemoryInputStream is created. -*/ -class JUCE_API MemoryInputStream : public InputStream -{ -public: + The object that gets returned will be owned by the caller. - /** Creates a MemoryInputStream. + This method can only be called after using createListener(). - @param sourceData the block of data to use as the stream's source - @param sourceDataSize the number of bytes in the source data block - @param keepInternalCopyOfData if false, the stream will just keep a pointer to - the source data, so this data shouldn't be changed - for the lifetime of the stream; if this parameter is - true, the stream will make its own copy of the - data and use that. + @see createListener */ - MemoryInputStream (const void* const sourceData, - const int sourceDataSize, - const bool keepInternalCopyOfData) throw(); - - /** Destructor. */ - ~MemoryInputStream() throw(); - - int64 getPosition(); - bool setPosition (int64 pos); - int64 getTotalLength(); - bool isExhausted(); - int read (void* destBuffer, int maxBytesToRead); + StreamingSocket* waitForNextConnection() const; juce_UseDebuggingNewOperator private: - const char* data; - int dataSize, position; - MemoryBlock internalCopy; -}; - -#endif // __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_MemoryInputStream.h *********/ + String hostName; + int volatile portNumber, handle; + bool connected, isListener; -#endif -#ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ + StreamingSocket (const String& hostname, const int portNumber, const int handle); + StreamingSocket (const StreamingSocket&); + const StreamingSocket& operator= (const StreamingSocket&); +}; -/********* Start of inlined file: juce_MemoryOutputStream.h *********/ -#ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ -#define __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ +/** + A wrapper for a datagram (UDP) socket. -/** Writes data to an internal memory buffer, which grows as required. + This allows low-level use of sockets; for an easier-to-use messaging layer on top of + sockets, you could also try the InterprocessConnection class. - The data that was written into the stream can then be accessed later as - a contiguous block of memory. + @see StreamingSocket, InterprocessConnection, InterprocessConnectionServer */ -class JUCE_API MemoryOutputStream : public OutputStream +class JUCE_API DatagramSocket { public: - /** Creates a memory stream ready for writing into. + /** + Creates an (uninitialised) datagram socket. - @param initialSize the intial amount of space to allocate for writing into - @param granularity the increments by which the internal storage will be increased - @param memoryBlockToWriteTo if this is non-zero, then this block will be used as the - place that the data gets stored. If it's zero, the stream - will allocate its own storage internally, which you can - access using getData() and getDataSize() - */ - MemoryOutputStream (const int initialSize = 256, - const int granularity = 256, - MemoryBlock* const memoryBlockToWriteTo = 0) throw(); + The localPortNumber is the port on which to bind this socket. If this value is 0, + the port number is assigned by the operating system. - /** Destructor. + To use the socket for sending, call the connect() method. This will not immediately + make a connection, but will save the destination you've provided. After this, you can + call read() or write(). - This will free any data that was written to it. + If enableBroadcasting is true, the socket will be allowed to send broadcast messages + (may require extra privileges on linux) + + To wait for other sockets to connect to this one, call waitForNextConnection(). */ - ~MemoryOutputStream() throw(); + DatagramSocket (const int localPortNumber, + const bool enableBroadcasting = false); - /** Returns a pointer to the data that has been written to the stream. + /** Destructor. */ + ~DatagramSocket(); - @see getDataSize + /** Binds the socket to the specified local port. + + @returns true on success; false may indicate that another socket is already bound + on the same port */ - const char* getData() throw(); + bool bindToPort (const int localPortNumber); - /** Returns the number of bytes of data that have been written to the stream. + /** Tries to connect the socket to hostname:port. - @see getData + If timeOutMillisecs is 0, then this method will block until the operating system + rejects the connection (which could take a long time). + + @returns true if it succeeds. + @see isConnected */ - int getDataSize() const throw(); + bool connect (const String& remoteHostname, + const int remotePortNumber, + const int timeOutMillisecs = 3000); - /** Resets the stream, clearing any data that has been written to it so far. */ - void reset() throw(); + /** True if the socket is currently connected. */ + bool isConnected() const throw() { return connected; } - void flush(); - bool write (const void* buffer, int howMany); - int64 getPosition(); - bool setPosition (int64 newPosition); + /** Closes the connection. */ + void close(); - juce_UseDebuggingNewOperator + /** Returns the name of the currently connected host. */ + const String& getHostName() const throw() { return hostName; } -private: - MemoryBlock* data; - int position, size, blockSize; - bool ownsMemoryBlock; -}; + /** Returns the port number that's currently open. */ + int getPort() const throw() { return portNumber; } -#endif // __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_MemoryOutputStream.h *********/ + /** True if the socket is connected to this machine rather than over the network. */ + bool isLocal() const throw(); -#endif -#ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ + /** Waits until the socket is ready for reading or writing. -#endif -#ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ + If readyForReading is true, it will wait until the socket is ready for + reading; if false, it will wait until it's ready for writing. -/********* Start of inlined file: juce_SubregionStream.h *********/ -#ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ -#define __JUCE_SUBREGIONSTREAM_JUCEHEADER__ + If the timeout is < 0, it will wait forever, or else will give up after + the specified time. -/** Wraps another input stream, and reads from a specific part of it. + If the socket is ready on return, this returns 1. If it times-out before + the socket becomes ready, it returns 0. If an error occurs, it returns -1. + */ + int waitUntilReady (const bool readyForReading, + const int timeoutMsecs) const; - This lets you take a subsection of a stream and present it as an entire - stream in its own right. -*/ -class JUCE_API SubregionStream : public InputStream -{ -public: + /** Reads bytes from the socket. - /** Creates a SubregionStream from an input source. + If blockUntilSpecifiedAmountHasArrived is true, the method will block until + maxBytesToRead bytes have been read, (or until an error occurs). If this + flag is false, the method will return as much data as is currently available + without blocking. - @param sourceStream the source stream to read from - @param startPositionInSourceStream this is the position in the source stream that - corresponds to position 0 in this stream - @param lengthOfSourceStream this specifies the maximum number of bytes - from the source stream that will be passed through - by this stream. When the position of this stream - exceeds lengthOfSourceStream, it will cause an end-of-stream. - If the length passed in here is greater than the length - of the source stream (as returned by getTotalLength()), - then the smaller value will be used. - Passing a negative value for this parameter means it - will keep reading until the source's end-of-stream. - @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be - deleted by this object when it is itself deleted. + @returns the number of bytes read, or -1 if there was an error. + @see waitUntilReady */ - SubregionStream (InputStream* const sourceStream, - const int64 startPositionInSourceStream, - const int64 lengthOfSourceStream, - const bool deleteSourceWhenDestroyed) throw(); + int read (void* destBuffer, const int maxBytesToRead, + const bool blockUntilSpecifiedAmountHasArrived); - /** Destructor. + /** Writes bytes to the socket from a buffer. - This may also delete the source stream, if that option was chosen when the - buffered stream was created. + Note that this method will block unless you have checked the socket is ready + for writing before calling it (see the waitUntilReady() method). + + @returns the number of bytes written, or -1 if there was an error. */ - ~SubregionStream() throw(); + int write (const void* sourceBuffer, const int numBytesToWrite); - int64 getTotalLength(); - int64 getPosition(); - bool setPosition (int64 newPosition); - int read (void* destBuffer, int maxBytesToRead); - bool isExhausted(); + /** This waits for incoming data to be sent, and returns a socket that can be used + to read it. + + The object that gets returned is owned by the caller, and can't be used for + sending, but can be used to read the data. + */ + DatagramSocket* waitForNextConnection() const; juce_UseDebuggingNewOperator private: - InputStream* const source; - const bool deleteSourceWhenDestroyed; - const int64 startPositionInSourceStream, lengthOfSourceStream; + String hostName; + int volatile portNumber, handle; + bool connected, allowBroadcast; + void* serverAddress; - SubregionStream (const SubregionStream&); - const SubregionStream& operator= (const SubregionStream&); + DatagramSocket (const String& hostname, const int portNumber, const int handle, const int localPortNumber); + DatagramSocket (const DatagramSocket&); + const DatagramSocket& operator= (const DatagramSocket&); }; -#endif // __JUCE_SUBREGIONSTREAM_JUCEHEADER__ -/********* End of inlined file: juce_SubregionStream.h *********/ +#endif // __JUCE_SOCKET_JUCEHEADER__ +/********* End of inlined file: juce_Socket.h *********/ #endif -#ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ +#ifndef __JUCE_URL_JUCEHEADER__ -/********* Start of inlined file: juce_LocalisedStrings.h *********/ -#ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ -#define __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ +/********* Start of inlined file: juce_URL.h *********/ +#ifndef __JUCE_URL_JUCEHEADER__ +#define __JUCE_URL_JUCEHEADER__ -/** Used in the same way as the T(text) macro, this will attempt to translate a - string into a localised version using the LocalisedStrings class. +/** + Represents a URL and has a bunch of useful functions to manipulate it. - @see LocalisedStrings + This class can be used to launch URLs in browsers, and also to create + InputStreams that can read from remote http or ftp sources. */ -#define TRANS(stringLiteral) \ - LocalisedStrings::translateWithCurrentMappings (stringLiteral) - -/** - Used to convert strings to localised foreign-language versions. +class JUCE_API URL +{ +public: - This is basically a look-up table of strings and their translated equivalents. - It can be loaded from a text file, so that you can supply a set of localised - versions of strings that you use in your app. + /** Creates an empty URL. */ + URL() throw(); - To use it in your code, simply call the translate() method on each string that - might have foreign versions, and if none is found, the method will just return - the original string. + /** Creates a URL from a string. */ + URL (const String& url); - The translation file should start with some lines specifying a description of - the language it contains, and also a list of ISO country codes where it might - be appropriate to use the file. After that, each line of the file should contain - a pair of quoted strings with an '=' sign. + /** Creates a copy of another URL. */ + URL (const URL& other); - E.g. for a french translation, the file might be: + /** Destructor. */ + ~URL() throw(); - @code - language: French - countries: fr be mc ch lu + /** Copies this URL from another one. */ + const URL& operator= (const URL& other); - "hello" = "bonjour" - "goodbye" = "au revoir" - @endcode + /** Returns a string version of the URL. - If the strings need to contain a quote character, they can use '\"' instead, and - if the first non-whitespace character on a line isn't a quote, then it's ignored, - (you can use this to add comments). + If includeGetParameters is true and any parameters have been set with the + withParameter() method, then the string will have these appended on the + end and url-encoded. + */ + const String toString (const bool includeGetParameters) const; - Note that this is a singleton class, so don't create or destroy the object directly. - There's also a TRANS(text) macro defined to make it easy to use the this. + /** True if it seems to be valid. */ + bool isWellFormed() const; - E.g. @code - printSomething (TRANS("hello")); - @endcode + /** Returns just the domain part of the URL. - This macro is used in the Juce classes themselves, so your application has a chance to - intercept and translate any internal Juce text strings that might be shown. (You can easily - get a list of all the messages by searching for the TRANS() macro in the Juce source - code). -*/ -class JUCE_API LocalisedStrings -{ -public: + E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". + */ + const String getDomain() const; - /** Creates a set of translations from the text of a translation file. + /** Returns the path part of the URL. - When you create one of these, you can call setCurrentMappings() to make it - the set of mappings that the system's using. + E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". */ - LocalisedStrings (const String& fileContents) throw(); + const String getSubPath() const; - /** Creates a set of translations from a file. + /** Returns the scheme of the URL. - When you create one of these, you can call setCurrentMappings() to make it - the set of mappings that the system's using. + E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't + include the colon). */ - LocalisedStrings (const File& fileToLoad) throw(); + const String getScheme() const; - /** Destructor. */ - ~LocalisedStrings() throw(); + /** Returns a new version of this URL that uses a different sub-path. - /** Selects the current set of mappings to be used by the system. + E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with + "bar", it'll return "http://www.xyz.com/bar?x=1". + */ + const URL withNewSubPath (const String& newPath) const; - The object you pass in will be automatically deleted when no longer needed, so - don't keep a pointer to it. You can also pass in zero to remove the current - mappings. + /** Returns a copy of this URL, with a GET parameter added to the end. - See also the TRANS() macro, which uses the current set to do its translation. + Any control characters in the value will be encoded. - @see translateWithCurrentMappings + e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com" + would produce a new url whose toString(true) method would return + "www.fish.com?amount=some+fish". */ - static void setCurrentMappings (LocalisedStrings* newTranslations) throw(); + const URL withParameter (const String& parameterName, + const String& parameterValue) const; - /** Returns the currently selected set of mappings. + /** Returns a copy of this URl, with a file-upload type parameter added to it. - This is the object that was last passed to setCurrentMappings(). It may - be 0 if none has been created. + When performing a POST where one of your parameters is a binary file, this + lets you specify the file. + + Note that the filename is stored, but the file itself won't actually be read + until this URL is later used to create a network input stream. */ - static LocalisedStrings* getCurrentMappings() throw(); + const URL withFileToUpload (const String& parameterName, + const File& fileToUpload, + const String& mimeType) const; - /** Tries to translate a string using the currently selected set of mappings. + /** Returns a set of all the parameters encoded into the url. - If no mapping has been set, or if the mapping doesn't contain a translation - for the string, this will just return the original string. + E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would + contain two pairs: "type" => "haddock" and "amount" => "some fish". - See also the TRANS() macro, which uses this method to do its translation. + The values returned will have been cleaned up to remove any escape characters. - @see setCurrentMappings, getCurrentMappings + @see getNamedParameter, withParameter */ - static const String translateWithCurrentMappings (const String& text) throw(); - - /** Tries to translate a string using the currently selected set of mappings. + const StringPairArray& getParameters() const throw(); - If no mapping has been set, or if the mapping doesn't contain a translation - for the string, this will just return the original string. + /** Returns the set of files that should be uploaded as part of a POST operation. - See also the TRANS() macro, which uses this method to do its translation. + This is the set of files that were added to the URL with the withFileToUpload() + method. + */ + const StringPairArray& getFilesToUpload() const throw(); - @see setCurrentMappings, getCurrentMappings + /** Returns the set of mime types associated with each of the upload files. */ - static const String translateWithCurrentMappings (const char* text) throw(); + const StringPairArray& getMimeTypesOfUploadFiles() const throw(); - /** Attempts to look up a string and return its localised version. + /** Returns a copy of this URL, with a block of data to send as the POST data. - If the string isn't found in the list, the original string will be returned. - */ - const String translate (const String& text) const throw(); + If you're setting the POST data, be careful not to have any parameters set + as well, otherwise it'll all get thrown in together, and might not have the + desired effect. - /** Returns the name of the language specified in the translation file. + If the URL already contains some POST data, this will replace it, rather + than being appended to it. - This is specified in the file using a line starting with "language:", e.g. - @code - language: german - @endcode + This data will only be used if you specify a post operation when you call + createInputStream(). */ - const String getLanguageName() const throw() { return languageName; } + const URL withPOSTData (const String& postData) const; - /** Returns the list of suitable country codes listed in the translation file. + /** Returns the data that was set using withPOSTData(). + */ + const String getPostData() const throw() { return postData; } - These is specified in the file using a line starting with "countries:", e.g. - @code - countries: fr be mc ch lu - @endcode + /** Tries to launch the system's default browser to open the URL. - The country codes are supposed to be 2-character ISO complient codes. + Returns true if this seems to have worked. */ - const StringArray getCountryCodes() const throw() { return countryCodes; } + bool launchInDefaultBrowser() const; - /** Indicates whether to use a case-insensitive search when looking up a string. - This defaults to true. + /** Takes a guess as to whether a string might be a valid website address. + + This isn't foolproof! */ - void setIgnoresCase (const bool shouldIgnoreCase) throw(); + static bool isProbablyAWebsiteURL (const String& possibleURL); - juce_UseDebuggingNewOperator + /** Takes a guess as to whether a string might be a valid email address. -private: - String languageName; - StringArray countryCodes; - StringPairArray translations; + This isn't foolproof! + */ + static bool isProbablyAnEmailAddress (const String& possibleEmailAddress); - void loadFromText (const String& fileContents) throw(); -}; + /** This callback function can be used by the createInputStream() method. -#endif // __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ -/********* End of inlined file: juce_LocalisedStrings.h *********/ + It allows your app to receive progress updates during a lengthy POST operation. If you + want to continue the operation, this should return true, or false to abort. + */ + typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes); -#endif -#ifndef __JUCE_STRING_JUCEHEADER__ - -#endif -#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ - -#endif -#ifndef __JUCE_STRINGARRAY_JUCEHEADER__ - -#endif -#ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ - -#endif -#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ + /** Attempts to open a stream that can read from this URL. -/********* Start of inlined file: juce_XmlDocument.h *********/ -#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ -#define __JUCE_XMLDOCUMENT_JUCEHEADER__ + @param usePostCommand if true, it will try to do use a http 'POST' to pass + the paramters, otherwise it'll encode them into the + URL and do a 'GET'. + @param progressCallback if this is non-zero, it lets you supply a callback function + to keep track of the operation's progress. This can be useful + for lengthy POST operations, so that you can provide user feedback. + @param progressCallbackContext if a callback is specified, this value will be passed to + the function + @param extraHeaders if not empty, this string is appended onto the headers that + are used for the request. It must therefore be a valid set of HTML + header directives, separated by newlines. + @param connectionTimeOutMs if 0, this will use whatever default setting the OS chooses. If + a negative number, it will be infinite. Otherwise it specifies a + time in milliseconds. + */ + InputStream* createInputStream (const bool usePostCommand, + OpenStreamProgressCallback* const progressCallback = 0, + void* const progressCallbackContext = 0, + const String& extraHeaders = String::empty, + const int connectionTimeOutMs = 0) const; -/** - Parses a text-based XML document and creates an XmlElement object from it. + /** Tries to download the entire contents of this URL into a binary data block. - The parser will parse DTDs to load external entities but won't - check the document for validity against the DTD. + If it succeeds, this will return true and append the data it read onto the end + of the memory block. - e.g. - @code + @param destData the memory block to append the new data to + @param usePostCommand whether to use a POST command to get the data (uses + a GET command if this is false) + @see readEntireTextStream, readEntireXmlStream + */ + bool readEntireBinaryStream (MemoryBlock& destData, + const bool usePostCommand = false) const; - XmlDocument myDocument (File ("myfile.xml")); - XmlElement* mainElement = myDocument.getDocumentElement(); + /** Tries to download the entire contents of this URL as a string. - if (mainElement == 0) - { - String error = myDocument.getLastParseError(); - } - else - { - ..use the element - } + If it fails, this will return an empty string, otherwise it will return the + contents of the downloaded file. If you need to distinguish between a read + operation that fails and one that returns an empty string, you'll need to use + a different method, such as readEntireBinaryStream(). - @endcode + @param usePostCommand whether to use a POST command to get the data (uses + a GET command if this is false) + @see readEntireBinaryStream, readEntireXmlStream + */ + const String readEntireTextStream (const bool usePostCommand = false) const; - @see XmlElement -*/ -class JUCE_API XmlDocument -{ -public: + /** Tries to download the entire contents of this URL and parse it as XML. - /** Creates an XmlDocument from the xml text. + If it fails, or if the text that it reads can't be parsed as XML, this will + return 0. - The text doesn't actually get parsed until the getDocumentElement() method is - called. - */ - XmlDocument (const String& documentText) throw(); + When it returns a valid XmlElement object, the caller is responsibile for deleting + this object when no longer needed. - /** Creates an XmlDocument from a file. + @param usePostCommand whether to use a POST command to get the data (uses + a GET command if this is false) - The text doesn't actually get parsed until the getDocumentElement() method is - called. + @see readEntireBinaryStream, readEntireTextStream */ - XmlDocument (const File& file); - - /** Destructor. */ - ~XmlDocument() throw(); + XmlElement* readEntireXmlStream (const bool usePostCommand = false) const; - /** Creates an XmlElement object to represent the main document node. + /** Adds escape sequences to a string to encode any characters that aren't + legal in a URL. - This method will do the actual parsing of the text, and if there's a - parse error, it may returns 0 (and you can find out the error using - the getLastParseError() method). + E.g. any spaces will be replaced with "%20". - @param onlyReadOuterDocumentElement if true, the parser will only read the - first section of the file, and will only - return the outer document element - this - allows quick checking of large files to - see if they contain the correct type of - tag, without having to parse the entire file - @returns a new XmlElement which the caller will need to delete, or null if - there was an error. - @see getLastParseError - */ - XmlElement* getDocumentElement (const bool onlyReadOuterDocumentElement = false); + This is the opposite of removeEscapeChars(). - /** Returns the parsing error that occurred the last time getDocumentElement was called. + If isParameter is true, it means that the string is going to be used + as a parameter, so it also encodes '$' and ',' (which would otherwise + be legal in a URL. - @returns the error, or an empty string if there was no error. + @see removeEscapeChars */ - const String& getLastParseError() const throw(); - - /** Sets an input source object to use for parsing documents that reference external entities. - - If the document has been created from a file, this probably won't be needed, but - if you're parsing some text and there might be a DTD that references external - files, you may need to create a custom input source that can retrieve the - other files it needs. + static const String addEscapeChars (const String& stringToAddEscapeCharsTo, + const bool isParameter); - The object that is passed-in will be deleted automatically when no longer needed. + /** Replaces any escape character sequences in a string with their original + character codes. - @see InputSource - */ - void setInputSource (InputSource* const newSource) throw(); + E.g. any instances of "%20" will be replaced by a space. - /** Sets a flag to change the treatment of empty text elements. + This is the opposite of addEscapeChars(). - If this is true (the default state), then any text elements that contain only - whitespace characters will be ingored during parsing. If you need to catch - whitespace-only text, then you should set this to false before calling the - getDocumentElement() method. + @see addEscapeChars */ - void setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw(); + static const String removeEscapeChars (const String& stringToRemoveEscapeCharsFrom); juce_UseDebuggingNewOperator private: - String originalText; - const tchar* input; - bool outOfData, errorOccurred; - - bool identifierLookupTable [128]; - String lastError, dtdText; - StringArray tokenisedDTD; - bool needToLoadDTD, ignoreEmptyTextElements; - InputSource* inputSource; - - void setLastError (const String& desc, const bool carryOn) throw(); - void skipHeader() throw(); - void skipNextWhiteSpace() throw(); - tchar readNextChar() throw(); - XmlElement* readNextElement (const bool alsoParseSubElements) throw(); - void readChildElements (XmlElement* parent) throw(); - int findNextTokenLength() throw(); - void readQuotedString (String& result) throw(); - void readEntity (String& result) throw(); - - const String getFileContents (const String& filename) const; - const String expandEntity (const String& entity); - const String expandExternalEntity (const String& entity); - const String getParameterEntity (const String& entity); + String url, postData; + StringPairArray parameters, filesToUpload, mimeTypes; }; -#endif // __JUCE_XMLDOCUMENT_JUCEHEADER__ -/********* End of inlined file: juce_XmlDocument.h *********/ - -#endif -#ifndef __JUCE_XMLELEMENT_JUCEHEADER__ - -#endif -#ifndef __JUCE_CRITICALSECTION_JUCEHEADER__ +#endif // __JUCE_URL_JUCEHEADER__ +/********* End of inlined file: juce_URL.h *********/ #endif -#ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ +#ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ -/********* Start of inlined file: juce_InterProcessLock.h *********/ -#ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ -#define __JUCE_INTERPROCESSLOCK_JUCEHEADER__ +/********* Start of inlined file: juce_BufferedInputStream.h *********/ +#ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ +#define __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ -/** - Acts as a critical section which processes can use to block each other. +/** Wraps another input stream, and reads from it using an intermediate buffer - @see CriticalSection + If you're using an input stream such as a file input stream, and making lots of + small read accesses to it, it's probably sensible to wrap it in one of these, + so that the source stream gets accessed in larger chunk sizes, meaning less + work for the underlying stream. */ -class JUCE_API InterProcessLock +class JUCE_API BufferedInputStream : public InputStream { public: - /** Creates a lock object. + /** Creates a BufferedInputStream from an input source. - @param name a name that processes will use to identify this lock object + @param sourceStream the source stream to read from + @param bufferSize the size of reservoir to use to buffer the source + @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be + deleted by this object when it is itself deleted. */ - InterProcessLock (const String& name) throw(); + BufferedInputStream (InputStream* const sourceStream, + const int bufferSize, + const bool deleteSourceWhenDestroyed) throw(); /** Destructor. - This will also release the lock if it's currently held by this process. - */ - ~InterProcessLock() throw(); - - /** Attempts to lock the critical section. - - @param timeOutMillisecs how many milliseconds to wait if the lock - is already held by another process - a value of - 0 will return immediately, negative values will wait - forever - @returns true if the lock could be gained within the timeout period, or - false if the timeout expired. + This may also delete the source stream, if that option was chosen when the + buffered stream was created. */ - bool enter (int timeOutMillisecs = -1) throw(); + ~BufferedInputStream() throw(); - /** Releases the lock if it's currently held by this process. - */ - void exit() throw(); + int64 getTotalLength(); + int64 getPosition(); + bool setPosition (int64 newPosition); + int read (void* destBuffer, int maxBytesToRead); + const String readString(); + bool isExhausted(); juce_UseDebuggingNewOperator private: + InputStream* const source; + const bool deleteSourceWhenDestroyed; + int bufferSize; + int64 position, lastReadPos, bufferStart, bufferOverlap; + HeapBlock buffer; + void ensureBuffered(); - void* internal; - String name; - int reentrancyLevel; - - InterProcessLock (const InterProcessLock&); - const InterProcessLock& operator= (const InterProcessLock&); + BufferedInputStream (const BufferedInputStream&); + const BufferedInputStream& operator= (const BufferedInputStream&); }; -#endif // __JUCE_INTERPROCESSLOCK_JUCEHEADER__ -/********* End of inlined file: juce_InterProcessLock.h *********/ +#endif // __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_BufferedInputStream.h *********/ #endif -#ifndef __JUCE_PROCESS_JUCEHEADER__ - -/********* Start of inlined file: juce_Process.h *********/ -#ifndef __JUCE_PROCESS_JUCEHEADER__ -#define __JUCE_PROCESS_JUCEHEADER__ +#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ -/** Represents the current executable's process. +/********* Start of inlined file: juce_FileInputSource.h *********/ +#ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ +#define __JUCE_FILEINPUTSOURCE_JUCEHEADER__ - This contains methods for controlling the current application at the - process-level. +/** + A type of InputSource that represents a normal file. - @see Thread, JUCEApplication + @see InputSource */ -class JUCE_API Process +class JUCE_API FileInputSource : public InputSource { public: - enum ProcessPriority - { - LowPriority = 0, - NormalPriority = 1, - HighPriority = 2, - RealtimePriority = 3 - }; - - /** Changes the current process's priority. - - @param priority the process priority, where - 0=low, 1=normal, 2=high, 3=realtime - */ - static void setPriority (const ProcessPriority priority); - - /** Kills the current process immediately. - - This is an emergency process terminator that kills the application - immediately - it's intended only for use only when something goes - horribly wrong. - - @see JUCEApplication::quit - */ - static void terminate(); - - /** Returns true if this application process is the one that the user is - currently using. - */ - static bool isForegroundProcess() throw(); - - /** Raises the current process's privilege level. + FileInputSource (const File& file) throw(); + ~FileInputSource(); - Does nothing if this isn't supported by the current OS, or if process - privilege level is fixed. - */ - static void raisePrivilege(); + InputStream* createInputStream(); + InputStream* createInputStreamFor (const String& relatedItemPath); + int64 hashCode() const; - /** Lowers the current process's privilege level. + juce_UseDebuggingNewOperator - Does nothing if this isn't supported by the current OS, or if process - privilege level is fixed. - */ - static void lowerPrivilege(); +private: + const File file; - /** Returns true if this process is being hosted by a debugger. - */ - static bool JUCE_CALLTYPE isRunningUnderDebugger() throw(); + FileInputSource (const FileInputSource&); + const FileInputSource& operator= (const FileInputSource&); }; -#endif // __JUCE_PROCESS_JUCEHEADER__ -/********* End of inlined file: juce_Process.h *********/ +#endif // __JUCE_FILEINPUTSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_FileInputSource.h *********/ #endif -#ifndef __JUCE_READWRITELOCK_JUCEHEADER__ - -/********* Start of inlined file: juce_ReadWriteLock.h *********/ -#ifndef __JUCE_READWRITELOCK_JUCEHEADER__ -#define __JUCE_READWRITELOCK_JUCEHEADER__ +#ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ -/********* Start of inlined file: juce_WaitableEvent.h *********/ -#ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ -#define __JUCE_WAITABLEEVENT_JUCEHEADER__ +/********* Start of inlined file: juce_GZIPCompressorOutputStream.h *********/ +#ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ +#define __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ /** - Allows threads to wait for events triggered by other threads. + A stream which uses zlib to compress the data written into it. - A thread can call wait() on a WaitableObject, and this will suspend the - calling thread until another thread wakes it up by calling the signal() - method. + @see GZIPDecompressorInputStream */ -class JUCE_API WaitableEvent +class JUCE_API GZIPCompressorOutputStream : public OutputStream { public: - /** Creates a WaitableEvent object. */ - WaitableEvent() throw(); - - /** Destructor. - - If other threads are waiting on this object when it gets deleted, this - can cause nasty errors, so be careful! - */ - ~WaitableEvent() throw(); - - /** Suspends the calling thread until the event has been signalled. - - This will wait until the object's signal() method is called by another thread, - or until the timeout expires. - - After the event has been signalled, this method will return true and reset - the event. - - @param timeOutMilliseconds the maximum time to wait, in milliseconds. A negative - value will cause it to wait forever. - - @returns true if the object has been signalled, false if the timeout expires first. - @see signal, reset - */ - bool wait (const int timeOutMilliseconds = -1) const throw(); - - /** Wakes up any threads that are currently waiting on this object. - - If signal() is called when nothing is waiting, the next thread to call wait() - will return immediately and reset the signal. + /** Creates a compression stream. - @see wait, reset + @param destStream the stream into which the compressed data should + be written + @param compressionLevel how much to compress the data, between 1 and 9, where + 1 is the fastest/lowest compression, and 9 is the + slowest/highest compression. Any value outside this range + indicates that a default compression level should be used. + @param deleteDestStreamWhenDestroyed whether or not to delete the destStream object when + this stream is destroyed + @param noWrap this is used internally by the ZipFile class + and should be ignored by user applications */ - void signal() const throw(); + GZIPCompressorOutputStream (OutputStream* const destStream, + int compressionLevel = 0, + const bool deleteDestStreamWhenDestroyed = false, + const bool noWrap = false); - /** Resets the event to an unsignalled state. + /** Destructor. */ + ~GZIPCompressorOutputStream(); - If it's not already signalled, this does nothing. - */ - void reset() const throw(); + void flush(); + int64 getPosition(); + bool setPosition (int64 newPosition); + bool write (const void* destBuffer, int howMany); juce_UseDebuggingNewOperator private: - void* internal; + OutputStream* const destStream; + const bool deleteDestStream; + HeapBlock buffer; + void* helper; + bool doNextBlock(); - WaitableEvent (const WaitableEvent&); - const WaitableEvent& operator= (const WaitableEvent&); + GZIPCompressorOutputStream (const GZIPCompressorOutputStream&); + const GZIPCompressorOutputStream& operator= (const GZIPCompressorOutputStream&); }; -#endif // __JUCE_WAITABLEEVENT_JUCEHEADER__ -/********* End of inlined file: juce_WaitableEvent.h *********/ +#endif // __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_GZIPCompressorOutputStream.h *********/ -/********* Start of inlined file: juce_Thread.h *********/ -#ifndef __JUCE_THREAD_JUCEHEADER__ -#define __JUCE_THREAD_JUCEHEADER__ +#endif +#ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ -/** - Encapsulates a thread. +/********* Start of inlined file: juce_GZIPDecompressorInputStream.h *********/ +#ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ +#define __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ - Subclasses derive from Thread and implement the run() method, in which they - do their business. The thread can then be started with the startThread() method - and controlled with various other methods. +/** + This stream will decompress a source-stream using zlib. - This class also contains some thread-related static methods, such - as sleep(), yield(), getCurrentThreadId() etc. + Tip: if you're reading lots of small items from one of these streams, you + can increase the performance enormously by passing it through a + BufferedInputStream, so that it has to read larger blocks less often. - @see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow, - MessageManagerLock + @see GZIPCompressorOutputStream */ -class JUCE_API Thread +class JUCE_API GZIPDecompressorInputStream : public InputStream { public: - /** - Creates a thread. + /** Creates a decompressor stream. - When first created, the thread is not running. Use the startThread() - method to start it. + @param sourceStream the stream to read from + @param deleteSourceWhenDestroyed whether or not to delete the source stream + when this object is destroyed + @param noWrap this is used internally by the ZipFile class + and should be ignored by user applications + @param uncompressedStreamLength if the creator knows the length that the + uncompressed stream will be, then it can supply this + value, which will be returned by getTotalLength() */ - Thread (const String& threadName); + GZIPDecompressorInputStream (InputStream* const sourceStream, + const bool deleteSourceWhenDestroyed, + const bool noWrap = false, + const int64 uncompressedStreamLength = -1); - /** Destructor. + /** Destructor. */ + ~GZIPDecompressorInputStream(); - Deleting a Thread object that is running will only give the thread a - brief opportunity to stop itself cleanly, so it's recommended that you - should always call stopThread() with a decent timeout before deleting, - to avoid the thread being forcibly killed (which is a Bad Thing). - */ - virtual ~Thread(); + int64 getPosition(); + bool setPosition (int64 pos); + int64 getTotalLength(); + bool isExhausted(); + int read (void* destBuffer, int maxBytesToRead); - /** Must be implemented to perform the thread's actual code. + juce_UseDebuggingNewOperator - Remember that the thread must regularly check the threadShouldExit() - method whilst running, and if this returns true it should return from - the run() method as soon as possible to avoid being forcibly killed. +private: + InputStream* const sourceStream; + const int64 uncompressedStreamLength; + const bool deleteSourceWhenDestroyed, noWrap; + bool isEof; + int activeBufferSize; + int64 originalSourcePos, currentPos; + HeapBlock buffer; + void* helper; - @see threadShouldExit, startThread - */ - virtual void run() = 0; + GZIPDecompressorInputStream (const GZIPDecompressorInputStream&); + const GZIPDecompressorInputStream& operator= (const GZIPDecompressorInputStream&); +}; - // Thread control functions.. +#endif // __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_GZIPDecompressorInputStream.h *********/ - /** Starts the thread running. +#endif +#ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ - This will start the thread's run() method. - (if it's already started, startThread() won't do anything). +#endif +#ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ - @see stopThread - */ - void startThread() throw(); - - /** Starts the thread with a given priority. - - Launches the thread with a given priority, where 0 = lowest, 10 = highest. - If the thread is already running, its priority will be changed. - - @see startThread, setPriority - */ - void startThread (const int priority) throw(); +#endif +#ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ - /** Attempts to stop the thread running. +/********* Start of inlined file: juce_MemoryInputStream.h *********/ +#ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ +#define __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ - This method will cause the threadShouldExit() method to return true - and call notify() in case the thread is currently waiting. +/** + Allows a block of data and to be accessed as a stream. - Hopefully the thread will then respond to this by exiting cleanly, and - the stopThread method will wait for a given time-period for this to - happen. + This can either be used to refer to a shared block of memory, or can make its + own internal copy of the data when the MemoryInputStream is created. +*/ +class JUCE_API MemoryInputStream : public InputStream +{ +public: - If the thread is stuck and fails to respond after the time-out, it gets - forcibly killed, which is a very bad thing to happen, as it could still - be holding locks, etc. which are needed by other parts of your program. + /** Creates a MemoryInputStream. - @param timeOutMilliseconds The number of milliseconds to wait for the - thread to finish before killing it by force. A negative - value in here will wait forever. - @see signalThreadShouldExit, threadShouldExit, waitForThreadToExit, isThreadRunning + @param sourceData the block of data to use as the stream's source + @param sourceDataSize the number of bytes in the source data block + @param keepInternalCopyOfData if false, the stream will just keep a pointer to + the source data, so this data shouldn't be changed + for the lifetime of the stream; if this parameter is + true, the stream will make its own copy of the + data and use that. */ - void stopThread (const int timeOutMilliseconds) throw(); - - /** Returns true if the thread is currently active */ - bool isThreadRunning() const throw(); + MemoryInputStream (const void* const sourceData, + const int sourceDataSize, + const bool keepInternalCopyOfData) throw(); - /** Sets a flag to tell the thread it should stop. + /** Destructor. */ + ~MemoryInputStream() throw(); - Calling this means that the threadShouldExit() method will then return true. - The thread should be regularly checking this to see whether it should exit. + int64 getPosition(); + bool setPosition (int64 pos); + int64 getTotalLength(); + bool isExhausted(); + int read (void* destBuffer, int maxBytesToRead); - @see threadShouldExit - @see waitForThreadToExit - */ - void signalThreadShouldExit() throw(); + juce_UseDebuggingNewOperator - /** Checks whether the thread has been told to stop running. +private: + const char* data; + int dataSize, position; + MemoryBlock internalCopy; +}; - Threads need to check this regularly, and if it returns true, they should - return from their run() method at the first possible opportunity. +#endif // __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_MemoryInputStream.h *********/ - @see signalThreadShouldExit - */ - inline bool threadShouldExit() const throw() { return threadShouldExit_; } +#endif +#ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ - /** Waits for the thread to stop. +/********* Start of inlined file: juce_MemoryOutputStream.h *********/ +#ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ +#define __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ - This will waits until isThreadRunning() is false or until a timeout expires. +/** Writes data to an internal memory buffer, which grows as required. - @param timeOutMilliseconds the time to wait, in milliseconds. If this value - is less than zero, it will wait forever. - @returns true if the thread exits, or false if the timeout expires first. - */ - bool waitForThreadToExit (const int timeOutMilliseconds) const throw(); + The data that was written into the stream can then be accessed later as + a contiguous block of memory. +*/ +class JUCE_API MemoryOutputStream : public OutputStream +{ +public: - /** Changes the thread's priority. - May return false if for some reason the priority can't be changed. + /** Creates a memory stream ready for writing into. - @param priority the new priority, in the range 0 (lowest) to 10 (highest). A priority - of 5 is normal. + @param initialSize the intial amount of space to allocate for writing into + @param granularity the increments by which the internal storage will be increased + @param memoryBlockToWriteTo if this is non-zero, then this block will be used as the + place that the data gets stored. If it's zero, the stream + will allocate its own storage internally, which you can + access using getData() and getDataSize() */ - bool setPriority (const int priority) throw(); - - /** Changes the priority of the caller thread. + MemoryOutputStream (const int initialSize = 256, + const int granularity = 256, + MemoryBlock* const memoryBlockToWriteTo = 0) throw(); - Similar to setPriority(), but this static method acts on the caller thread. - May return false if for some reason the priority can't be changed. + /** Destructor. - @see setPriority + This will free any data that was written to it. */ - static bool setCurrentThreadPriority (const int priority) throw(); - - /** Sets the affinity mask for the thread. + ~MemoryOutputStream() throw(); - This will only have an effect next time the thread is started - i.e. if the - thread is already running when called, it'll have no effect. + /** Returns a pointer to the data that has been written to the stream. - @see setCurrentThreadAffinityMask + @see getDataSize */ - void setAffinityMask (const uint32 affinityMask) throw(); - - /** Changes the affinity mask for the caller thread. + const char* getData() throw(); - This will change the affinity mask for the thread that calls this static method. + /** Returns the number of bytes of data that have been written to the stream. - @see setAffinityMask + @see getData */ - static void setCurrentThreadAffinityMask (const uint32 affinityMask) throw(); + int getDataSize() const throw(); - // this can be called from any thread that needs to pause.. - static void JUCE_CALLTYPE sleep (int milliseconds) throw(); + /** Resets the stream, clearing any data that has been written to it so far. */ + void reset() throw(); - /** Yields the calling thread's current time-slot. */ - static void JUCE_CALLTYPE yield() throw(); + void flush(); + bool write (const void* buffer, int howMany); + int64 getPosition(); + bool setPosition (int64 newPosition); - /** Makes the thread wait for a notification. + juce_UseDebuggingNewOperator - This puts the thread to sleep until either the timeout period expires, or - another thread calls the notify() method to wake it up. +private: + MemoryBlock* data; + int position, size, blockSize; + bool ownsMemoryBlock; +}; - @returns true if the event has been signalled, false if the timeout expires. - */ - bool wait (const int timeOutMilliseconds) const throw(); +#endif // __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_MemoryOutputStream.h *********/ - /** Wakes up the thread. +#endif +#ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ - If the thread has called the wait() method, this will wake it up. +#endif +#ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ - @see wait - */ - void notify() const throw(); +/********* Start of inlined file: juce_SubregionStream.h *********/ +#ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ +#define __JUCE_SUBREGIONSTREAM_JUCEHEADER__ - /** A value type used for thread IDs. - @see getCurrentThreadId(), getThreadId() - */ - typedef void* ThreadID; +/** Wraps another input stream, and reads from a specific part of it. - /** Returns an id that identifies the caller thread. + This lets you take a subsection of a stream and present it as an entire + stream in its own right. +*/ +class JUCE_API SubregionStream : public InputStream +{ +public: - To find the ID of a particular thread object, use getThreadId(). + /** Creates a SubregionStream from an input source. - @returns a unique identifier that identifies the calling thread. - @see getThreadId + @param sourceStream the source stream to read from + @param startPositionInSourceStream this is the position in the source stream that + corresponds to position 0 in this stream + @param lengthOfSourceStream this specifies the maximum number of bytes + from the source stream that will be passed through + by this stream. When the position of this stream + exceeds lengthOfSourceStream, it will cause an end-of-stream. + If the length passed in here is greater than the length + of the source stream (as returned by getTotalLength()), + then the smaller value will be used. + Passing a negative value for this parameter means it + will keep reading until the source's end-of-stream. + @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be + deleted by this object when it is itself deleted. */ - static ThreadID getCurrentThreadId() throw(); + SubregionStream (InputStream* const sourceStream, + const int64 startPositionInSourceStream, + const int64 lengthOfSourceStream, + const bool deleteSourceWhenDestroyed) throw(); - /** Finds the thread object that is currently running. + /** Destructor. - Note that the main UI thread (or other non-Juce threads) don't have a Thread - object associated with them, so this will return 0. + This may also delete the source stream, if that option was chosen when the + buffered stream was created. */ - static Thread* getCurrentThread() throw(); + ~SubregionStream() throw(); - /** Returns the ID of this thread. + int64 getTotalLength(); + int64 getPosition(); + bool setPosition (int64 newPosition); + int read (void* destBuffer, int maxBytesToRead); + bool isExhausted(); - That means the ID of this thread object - not of the thread that's calling the method. + juce_UseDebuggingNewOperator - This can change when the thread is started and stopped, and will be invalid if the - thread's not actually running. +private: + InputStream* const source; + const bool deleteSourceWhenDestroyed; + const int64 startPositionInSourceStream, lengthOfSourceStream; - @see getCurrentThreadId - */ - ThreadID getThreadId() const throw(); + SubregionStream (const SubregionStream&); + const SubregionStream& operator= (const SubregionStream&); +}; - /** Returns the name of the thread. +#endif // __JUCE_SUBREGIONSTREAM_JUCEHEADER__ +/********* End of inlined file: juce_SubregionStream.h *********/ - This is the name that gets set in the constructor. - */ - const String getThreadName() const throw() { return threadName_; } +#endif +#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ - /** Returns the number of currently-running threads. +#endif +#ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ - @returns the number of Thread objects known to be currently running. - @see stopAllThreads - */ - static int getNumRunningThreads() throw(); +/********* Start of inlined file: juce_LocalisedStrings.h *********/ +#ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ +#define __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ - /** Tries to stop all currently-running threads. +/** Used in the same way as the T(text) macro, this will attempt to translate a + string into a localised version using the LocalisedStrings class. - This will attempt to stop all the threads known to be running at the moment. - */ - static void stopAllThreads (const int timeoutInMillisecs) throw(); + @see LocalisedStrings +*/ +#define TRANS(stringLiteral) \ + LocalisedStrings::translateWithCurrentMappings (stringLiteral) - juce_UseDebuggingNewOperator +/** + Used to convert strings to localised foreign-language versions. -private: - const String threadName_; - void* volatile threadHandle_; - CriticalSection startStopLock; - WaitableEvent startSuspensionEvent_, defaultEvent_; + This is basically a look-up table of strings and their translated equivalents. + It can be loaded from a text file, so that you can supply a set of localised + versions of strings that you use in your app. - int threadPriority_; - ThreadID threadId_; - uint32 affinityMask_; - bool volatile threadShouldExit_; + To use it in your code, simply call the translate() method on each string that + might have foreign versions, and if none is found, the method will just return + the original string. - friend void JUCE_API juce_threadEntryPoint (void*); - static void threadEntryPoint (Thread* thread) throw(); + The translation file should start with some lines specifying a description of + the language it contains, and also a list of ISO country codes where it might + be appropriate to use the file. After that, each line of the file should contain + a pair of quoted strings with an '=' sign. - Thread (const Thread&); - const Thread& operator= (const Thread&); -}; + E.g. for a french translation, the file might be: -#endif // __JUCE_THREAD_JUCEHEADER__ -/********* End of inlined file: juce_Thread.h *********/ + @code + language: French + countries: fr be mc ch lu -/** - A critical section that allows multiple simultaneous readers. + "hello" = "bonjour" + "goodbye" = "au revoir" + @endcode - Features of this type of lock are: + If the strings need to contain a quote character, they can use '\"' instead, and + if the first non-whitespace character on a line isn't a quote, then it's ignored, + (you can use this to add comments). - - Multiple readers can hold the lock at the same time, but only one writer - can hold it at once. - - Writers trying to gain the lock will be blocked until all readers and writers - have released it - - Readers trying to gain the lock while a writer is waiting to acquire it will be - blocked until the writer has obtained and released it - - If a thread already has a read lock and tries to obtain a write lock, it will succeed if - there are no other readers - - If a thread already has the write lock and tries to obtain a read lock, this will succeed. - - Recursive locking is supported. + Note that this is a singleton class, so don't create or destroy the object directly. + There's also a TRANS(text) macro defined to make it easy to use the this. - @see ScopedReadLock, ScopedWriteLock, CriticalSection + E.g. @code + printSomething (TRANS("hello")); + @endcode + + This macro is used in the Juce classes themselves, so your application has a chance to + intercept and translate any internal Juce text strings that might be shown. (You can easily + get a list of all the messages by searching for the TRANS() macro in the Juce source + code). */ -class JUCE_API ReadWriteLock +class JUCE_API LocalisedStrings { public: - /** - Creates a ReadWriteLock object. + /** Creates a set of translations from the text of a translation file. + + When you create one of these, you can call setCurrentMappings() to make it + the set of mappings that the system's using. */ - ReadWriteLock() throw(); + LocalisedStrings (const String& fileContents) throw(); - /** Destructor. + /** Creates a set of translations from a file. - If the object is deleted whilst locked, any subsequent behaviour - is unpredictable. + When you create one of these, you can call setCurrentMappings() to make it + the set of mappings that the system's using. */ - ~ReadWriteLock() throw(); + LocalisedStrings (const File& fileToLoad) throw(); - /** Locks this object for reading. + /** Destructor. */ + ~LocalisedStrings() throw(); - Multiple threads can simulaneously lock the object for reading, but if another - thread has it locked for writing, then this will block until it releases the - lock. + /** Selects the current set of mappings to be used by the system. - @see exitRead, ScopedReadLock + The object you pass in will be automatically deleted when no longer needed, so + don't keep a pointer to it. You can also pass in zero to remove the current + mappings. + + See also the TRANS() macro, which uses the current set to do its translation. + + @see translateWithCurrentMappings */ - void enterRead() const throw(); + static void setCurrentMappings (LocalisedStrings* newTranslations) throw(); - /** Releases the read-lock. + /** Returns the currently selected set of mappings. - If the caller thread hasn't got the lock, this can have unpredictable results. + This is the object that was last passed to setCurrentMappings(). It may + be 0 if none has been created. + */ + static LocalisedStrings* getCurrentMappings() throw(); - If the enterRead() method has been called multiple times by the thread, each - call must be matched by a call to exitRead() before other threads will be allowed - to take over the lock. + /** Tries to translate a string using the currently selected set of mappings. - @see enterRead, ScopedReadLock + If no mapping has been set, or if the mapping doesn't contain a translation + for the string, this will just return the original string. + + See also the TRANS() macro, which uses this method to do its translation. + + @see setCurrentMappings, getCurrentMappings */ - void exitRead() const throw(); + static const String translateWithCurrentMappings (const String& text) throw(); - /** Locks this object for writing. + /** Tries to translate a string using the currently selected set of mappings. - This will block until any other threads that have it locked for reading or - writing have released their lock. + If no mapping has been set, or if the mapping doesn't contain a translation + for the string, this will just return the original string. - @see exitWrite, ScopedWriteLock + See also the TRANS() macro, which uses this method to do its translation. + + @see setCurrentMappings, getCurrentMappings */ - void enterWrite() const throw(); + static const String translateWithCurrentMappings (const char* text) throw(); - /** Tries to lock this object for writing. + /** Attempts to look up a string and return its localised version. - This is like enterWrite(), but doesn't block - it returns true if it manages - to obtain the lock. + If the string isn't found in the list, the original string will be returned. + */ + const String translate (const String& text) const throw(); - @see enterWrite + /** Returns the name of the language specified in the translation file. + + This is specified in the file using a line starting with "language:", e.g. + @code + language: german + @endcode */ - bool tryEnterWrite() const throw(); + const String getLanguageName() const throw() { return languageName; } - /** Releases the write-lock. + /** Returns the list of suitable country codes listed in the translation file. - If the caller thread hasn't got the lock, this can have unpredictable results. + These is specified in the file using a line starting with "countries:", e.g. + @code + countries: fr be mc ch lu + @endcode - If the enterWrite() method has been called multiple times by the thread, each - call must be matched by a call to exit() before other threads will be allowed - to take over the lock. + The country codes are supposed to be 2-character ISO complient codes. + */ + const StringArray getCountryCodes() const throw() { return countryCodes; } - @see enterWrite, ScopedWriteLock + /** Indicates whether to use a case-insensitive search when looking up a string. + This defaults to true. */ - void exitWrite() const throw(); + void setIgnoresCase (const bool shouldIgnoreCase) throw(); juce_UseDebuggingNewOperator private: + String languageName; + StringArray countryCodes; + StringPairArray translations; - CriticalSection accessLock; - WaitableEvent waitEvent; - mutable int numWaitingWriters, numWriters; - mutable Thread::ThreadID writerThreadId; - mutable Array readerThreads; - - ReadWriteLock (const ReadWriteLock&); - const ReadWriteLock& operator= (const ReadWriteLock&); + void loadFromText (const String& fileContents) throw(); }; -#endif // __JUCE_READWRITELOCK_JUCEHEADER__ -/********* End of inlined file: juce_ReadWriteLock.h *********/ +#endif // __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ +/********* End of inlined file: juce_LocalisedStrings.h *********/ #endif -#ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ +#ifndef __JUCE_STRING_JUCEHEADER__ #endif -#ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ +#ifndef __JUCE_STRINGARRAY_JUCEHEADER__ -/********* Start of inlined file: juce_ScopedReadLock.h *********/ -#ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ -#define __JUCE_SCOPEDREADLOCK_JUCEHEADER__ +#endif +#ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ -/** - Automatically locks and unlocks a ReadWriteLock object. +#endif +#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ - Use one of these as a local variable to control access to a ReadWriteLock. +/********* Start of inlined file: juce_XmlDocument.h *********/ +#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ +#define __JUCE_XMLDOCUMENT_JUCEHEADER__ - e.g. @code +/** + Parses a text-based XML document and creates an XmlElement object from it. - ReadWriteLock myLock; + The parser will parse DTDs to load external entities but won't + check the document for validity against the DTD. - for (;;) - { - const ScopedReadLock myScopedLock (myLock); - // myLock is now locked + e.g. + @code - ...do some stuff... + XmlDocument myDocument (File ("myfile.xml")); + XmlElement* mainElement = myDocument.getDocumentElement(); - // myLock gets unlocked here. + if (mainElement == 0) + { + String error = myDocument.getLastParseError(); + } + else + { + ..use the element } + @endcode - @see ReadWriteLock, ScopedWriteLock + @see XmlElement */ -class JUCE_API ScopedReadLock +class JUCE_API XmlDocument { public: - /** Creates a ScopedReadLock. - - As soon as it is created, this will call ReadWriteLock::enterRead(), and - when the ScopedReadLock object is deleted, the ReadWriteLock will - be unlocked. + /** Creates an XmlDocument from the xml text. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. + The text doesn't actually get parsed until the getDocumentElement() method is + called. */ - inline ScopedReadLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterRead(); } - - /** Destructor. + XmlDocument (const String& documentText) throw(); - The ReadWriteLock's exitRead() method will be called when the destructor is called. + /** Creates an XmlDocument from a file. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! + The text doesn't actually get parsed until the getDocumentElement() method is + called. */ - inline ~ScopedReadLock() throw() { lock_.exitRead(); } + XmlDocument (const File& file); -private: + /** Destructor. */ + ~XmlDocument() throw(); - const ReadWriteLock& lock_; + /** Creates an XmlElement object to represent the main document node. - ScopedReadLock (const ScopedReadLock&); - const ScopedReadLock& operator= (const ScopedReadLock&); -}; + This method will do the actual parsing of the text, and if there's a + parse error, it may returns 0 (and you can find out the error using + the getLastParseError() method). -#endif // __JUCE_SCOPEDREADLOCK_JUCEHEADER__ -/********* End of inlined file: juce_ScopedReadLock.h *********/ + @param onlyReadOuterDocumentElement if true, the parser will only read the + first section of the file, and will only + return the outer document element - this + allows quick checking of large files to + see if they contain the correct type of + tag, without having to parse the entire file + @returns a new XmlElement which the caller will need to delete, or null if + there was an error. + @see getLastParseError + */ + XmlElement* getDocumentElement (const bool onlyReadOuterDocumentElement = false); -#endif -#ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ + /** Returns the parsing error that occurred the last time getDocumentElement was called. -/********* Start of inlined file: juce_ScopedTryLock.h *********/ -#ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ -#define __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ + @returns the error, or an empty string if there was no error. + */ + const String& getLastParseError() const throw(); -/** - Automatically tries to lock and unlock a CriticalSection object. + /** Sets an input source object to use for parsing documents that reference external entities. - Use one of these as a local variable to control access to a CriticalSection. + If the document has been created from a file, this probably won't be needed, but + if you're parsing some text and there might be a DTD that references external + files, you may need to create a custom input source that can retrieve the + other files it needs. - e.g. @code + The object that is passed-in will be deleted automatically when no longer needed. - CriticalSection myCriticalSection; + @see InputSource + */ + void setInputSource (InputSource* const newSource) throw(); - for (;;) - { - const ScopedTryLock myScopedTryLock (myCriticalSection); + /** Sets a flag to change the treatment of empty text elements. - // Unlike using a ScopedLock, this may fail to actually get the lock, so you - // should test this with the isLocked() method before doing your thread-unsafe - // action.. - if (myScopedTryLock.isLocked()) - { - ...do some stuff... - } - else - { - ..our attempt at locking failed because another thread had already locked it.. - } + If this is true (the default state), then any text elements that contain only + whitespace characters will be ingored during parsing. If you need to catch + whitespace-only text, then you should set this to false before calling the + getDocumentElement() method. + */ + void setEmptyTextElementsIgnored (const bool shouldBeIgnored) throw(); - // myCriticalSection gets unlocked here (if it was locked) - } - @endcode + juce_UseDebuggingNewOperator - @see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock +private: + String originalText; + const tchar* input; + bool outOfData, errorOccurred; + + bool identifierLookupTable [128]; + String lastError, dtdText; + StringArray tokenisedDTD; + bool needToLoadDTD, ignoreEmptyTextElements; + InputSource* inputSource; + + void setLastError (const String& desc, const bool carryOn) throw(); + void skipHeader() throw(); + void skipNextWhiteSpace() throw(); + tchar readNextChar() throw(); + XmlElement* readNextElement (const bool alsoParseSubElements) throw(); + void readChildElements (XmlElement* parent) throw(); + int findNextTokenLength() throw(); + void readQuotedString (String& result) throw(); + void readEntity (String& result) throw(); + + const String getFileContents (const String& filename) const; + const String expandEntity (const String& entity); + const String expandExternalEntity (const String& entity); + const String getParameterEntity (const String& entity); +}; + +#endif // __JUCE_XMLDOCUMENT_JUCEHEADER__ +/********* End of inlined file: juce_XmlDocument.h *********/ + +#endif +#ifndef __JUCE_XMLELEMENT_JUCEHEADER__ + +#endif +#ifndef __JUCE_CRITICALSECTION_JUCEHEADER__ + +#endif +#ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ + +/********* Start of inlined file: juce_InterProcessLock.h *********/ +#ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ +#define __JUCE_INTERPROCESSLOCK_JUCEHEADER__ + +/** + Acts as a critical section which processes can use to block each other. + + @see CriticalSection */ -class JUCE_API ScopedTryLock +class JUCE_API InterProcessLock { public: - /** Creates a ScopedTryLock. - - As soon as it is created, this will try to lock the CriticalSection, and - when the ScopedTryLock object is deleted, the CriticalSection will - be unlocked if the lock was successful. + /** Creates a lock object. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. + @param name a name that processes will use to identify this lock object */ - inline ScopedTryLock (const CriticalSection& lock) throw() : lock_ (lock), lockWasSuccessful (lock.tryEnter()) {} + InterProcessLock (const String& name) throw(); /** Destructor. - The CriticalSection will be unlocked (if locked) when the destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! + This will also release the lock if it's currently held by this process. */ - inline ~ScopedTryLock() throw() { if (lockWasSuccessful) lock_.exit(); } + ~InterProcessLock() throw(); - /** Lock state + /** Attempts to lock the critical section. - @return True if the CriticalSection is locked. + @param timeOutMillisecs how many milliseconds to wait if the lock + is already held by another process - a value of + 0 will return immediately, negative values will wait + forever + @returns true if the lock could be gained within the timeout period, or + false if the timeout expired. */ - bool isLocked() const throw() { return lockWasSuccessful; } + bool enter (int timeOutMillisecs = -1) throw(); + + /** Releases the lock if it's currently held by this process. + */ + void exit() throw(); + + juce_UseDebuggingNewOperator private: - const CriticalSection& lock_; - const bool lockWasSuccessful; + void* internal; + String name; + int reentrancyLevel; - ScopedTryLock (const ScopedTryLock&); - const ScopedTryLock& operator= (const ScopedTryLock&); + InterProcessLock (const InterProcessLock&); + const InterProcessLock& operator= (const InterProcessLock&); }; -#endif // __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ -/********* End of inlined file: juce_ScopedTryLock.h *********/ +#endif // __JUCE_INTERPROCESSLOCK_JUCEHEADER__ +/********* End of inlined file: juce_InterProcessLock.h *********/ #endif -#ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ - -/********* Start of inlined file: juce_ScopedWriteLock.h *********/ -#ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ -#define __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ +#ifndef __JUCE_PROCESS_JUCEHEADER__ -/** - Automatically locks and unlocks a ReadWriteLock object. +/********* Start of inlined file: juce_Process.h *********/ +#ifndef __JUCE_PROCESS_JUCEHEADER__ +#define __JUCE_PROCESS_JUCEHEADER__ - Use one of these as a local variable to control access to a ReadWriteLock. +/** Represents the current executable's process. - e.g. @code + This contains methods for controlling the current application at the + process-level. - ReadWriteLock myLock; + @see Thread, JUCEApplication +*/ +class JUCE_API Process +{ +public: - for (;;) + enum ProcessPriority { - const ScopedWriteLock myScopedLock (myLock); - // myLock is now locked - - ...do some stuff... + LowPriority = 0, + NormalPriority = 1, + HighPriority = 2, + RealtimePriority = 3 + }; - // myLock gets unlocked here. - } - @endcode + /** Changes the current process's priority. - @see ReadWriteLock, ScopedReadLock -*/ -class JUCE_API ScopedWriteLock -{ -public: + @param priority the process priority, where + 0=low, 1=normal, 2=high, 3=realtime + */ + static void setPriority (const ProcessPriority priority); - /** Creates a ScopedWriteLock. + /** Kills the current process immediately. - As soon as it is created, this will call ReadWriteLock::enterWrite(), and - when the ScopedWriteLock object is deleted, the ReadWriteLock will - be unlocked. + This is an emergency process terminator that kills the application + immediately - it's intended only for use only when something goes + horribly wrong. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. + @see JUCEApplication::quit */ - inline ScopedWriteLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterWrite(); } + static void terminate(); - /** Destructor. + /** Returns true if this application process is the one that the user is + currently using. + */ + static bool isForegroundProcess() throw(); - The ReadWriteLock's exitWrite() method will be called when the destructor is called. + /** Raises the current process's privilege level. - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! + Does nothing if this isn't supported by the current OS, or if process + privilege level is fixed. */ - inline ~ScopedWriteLock() throw() { lock_.exitWrite(); } + static void raisePrivilege(); -private: + /** Lowers the current process's privilege level. - const ReadWriteLock& lock_; + Does nothing if this isn't supported by the current OS, or if process + privilege level is fixed. + */ + static void lowerPrivilege(); - ScopedWriteLock (const ScopedWriteLock&); - const ScopedWriteLock& operator= (const ScopedWriteLock&); + /** Returns true if this process is being hosted by a debugger. + */ + static bool JUCE_CALLTYPE isRunningUnderDebugger() throw(); }; -#endif // __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ -/********* End of inlined file: juce_ScopedWriteLock.h *********/ - -#endif -#ifndef __JUCE_THREAD_JUCEHEADER__ +#endif // __JUCE_PROCESS_JUCEHEADER__ +/********* End of inlined file: juce_Process.h *********/ #endif -#ifndef __JUCE_THREADPOOL_JUCEHEADER__ +#ifndef __JUCE_READWRITELOCK_JUCEHEADER__ -/********* Start of inlined file: juce_ThreadPool.h *********/ -#ifndef __JUCE_THREADPOOL_JUCEHEADER__ -#define __JUCE_THREADPOOL_JUCEHEADER__ +/********* Start of inlined file: juce_ReadWriteLock.h *********/ +#ifndef __JUCE_READWRITELOCK_JUCEHEADER__ +#define __JUCE_READWRITELOCK_JUCEHEADER__ -class ThreadPool; -class ThreadPoolThread; +/********* Start of inlined file: juce_WaitableEvent.h *********/ +#ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ +#define __JUCE_WAITABLEEVENT_JUCEHEADER__ /** - A task that is executed by a ThreadPool object. - - A ThreadPool keeps a list of ThreadPoolJob objects which are executed by - its threads. - - The runJob() method needs to be implemented to do the task, and if the code that - does the work takes a significant time to run, it must keep checking the shouldExit() - method to see if something is trying to interrupt the job. If shouldExit() returns - true, the runJob() method must return immediately. + Allows threads to wait for events triggered by other threads. - @see ThreadPool, Thread + A thread can call wait() on a WaitableObject, and this will suspend the + calling thread until another thread wakes it up by calling the signal() + method. */ -class JUCE_API ThreadPoolJob +class JUCE_API WaitableEvent { public: - /** Creates a thread pool job object. - - After creating your job, add it to a thread pool with ThreadPool::addJob(). - */ - ThreadPoolJob (const String& name); - - /** Destructor. */ - virtual ~ThreadPoolJob(); - - /** Returns the name of this job. - @see setJobName - */ - const String getJobName() const throw(); + /** Creates a WaitableEvent object. */ + WaitableEvent() throw(); - /** Changes the job's name. - @see getJobName - */ - void setJobName (const String& newName) throw(); + /** Destructor. - /** These are the values that can be returned by the runJob() method. + If other threads are waiting on this object when it gets deleted, this + can cause nasty errors, so be careful! */ - enum JobStatus - { - jobHasFinished = 0, /**< indicates that the job has finished and can be - removed from the pool. */ - - jobHasFinishedAndShouldBeDeleted, /**< indicates that the job has finished and that it - should be automatically deleted by the pool. */ - - jobNeedsRunningAgain /**< indicates that the job would like to be called - again when a thread is free. */ - }; + ~WaitableEvent() throw(); - /** Peforms the actual work that this job needs to do. + /** Suspends the calling thread until the event has been signalled. - Your subclass must implement this method, in which is does its work. + This will wait until the object's signal() method is called by another thread, + or until the timeout expires. - If the code in this method takes a significant time to run, it must repeatedly check - the shouldExit() method to see if something is trying to interrupt the job. - If shouldExit() ever returns true, the runJob() method must return immediately. + After the event has been signalled, this method will return true and reset + the event. - If this method returns jobHasFinished, then the job will be removed from the pool - immediately. If it returns jobNeedsRunningAgain, then the job will be left in the - pool and will get a chance to run again as soon as a thread is free. + @param timeOutMilliseconds the maximum time to wait, in milliseconds. A negative + value will cause it to wait forever. - @see shouldExit() + @returns true if the object has been signalled, false if the timeout expires first. + @see signal, reset */ - virtual JobStatus runJob() = 0; - - /** Returns true if this job is currently running its runJob() method. */ - bool isRunning() const throw() { return isActive; } + bool wait (const int timeOutMilliseconds = -1) const throw(); - /** Returns true if something is trying to interrupt this job and make it stop. + /** Wakes up any threads that are currently waiting on this object. - Your runJob() method must call this whenever it gets a chance, and if it ever - returns true, the runJob() method must return immediately. + If signal() is called when nothing is waiting, the next thread to call wait() + will return immediately and reset the signal. - @see signalJobShouldExit() + @see wait, reset */ - bool shouldExit() const throw() { return shouldStop; } + void signal() const throw(); - /** Calling this will cause the shouldExit() method to return true, and the job - should (if it's been implemented correctly) stop as soon as possible. + /** Resets the event to an unsignalled state. - @see shouldExit() + If it's not already signalled, this does nothing. */ - void signalJobShouldExit() throw(); + void reset() const throw(); juce_UseDebuggingNewOperator private: - friend class ThreadPool; - friend class ThreadPoolThread; - String jobName; - ThreadPool* pool; - bool shouldStop, isActive, shouldBeDeleted; + void* internal; - ThreadPoolJob (const ThreadPoolJob&); - const ThreadPoolJob& operator= (const ThreadPoolJob&); + WaitableEvent (const WaitableEvent&); + const WaitableEvent& operator= (const WaitableEvent&); }; +#endif // __JUCE_WAITABLEEVENT_JUCEHEADER__ +/********* End of inlined file: juce_WaitableEvent.h *********/ + +/********* Start of inlined file: juce_Thread.h *********/ +#ifndef __JUCE_THREAD_JUCEHEADER__ +#define __JUCE_THREAD_JUCEHEADER__ + /** - A set of threads that will run a list of jobs. + Encapsulates a thread. - When a ThreadPoolJob object is added to the ThreadPool's list, its run() method - will be called by the next pooled thread that becomes free. + Subclasses derive from Thread and implement the run() method, in which they + do their business. The thread can then be started with the startThread() method + and controlled with various other methods. - @see ThreadPoolJob, Thread + This class also contains some thread-related static methods, such + as sleep(), yield(), getCurrentThreadId() etc. + + @see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow, + MessageManagerLock */ -class JUCE_API ThreadPool +class JUCE_API Thread { public: - /** Creates a thread pool. - - Once you've created a pool, you can give it some things to do with the addJob() - method. + /** + Creates a thread. - @param numberOfThreads the maximum number of actual threads to run. - @param startThreadsOnlyWhenNeeded if this is true, then no threads will be started - until there are some jobs to run. If false, then - all the threads will be fired-up immediately so that - they're ready for action - @param stopThreadsWhenNotUsedTimeoutMs if this timeout is > 0, then if any threads have been - inactive for this length of time, they will automatically - be stopped until more jobs come along and they're needed + When first created, the thread is not running. Use the startThread() + method to start it. */ - ThreadPool (const int numberOfThreads, - const bool startThreadsOnlyWhenNeeded = true, - const int stopThreadsWhenNotUsedTimeoutMs = 5000); + Thread (const String& threadName); /** Destructor. - This will attempt to remove all the jobs before deleting, but if you want to - specify a timeout, you should call removeAllJobs() explicitly before deleting - the pool. - */ - ~ThreadPool(); - - /** A callback class used when you need to select which ThreadPoolJob objects are suitable - for some kind of operation. - @see ThreadPool::removeAllJobs + Deleting a Thread object that is running will only give the thread a + brief opportunity to stop itself cleanly, so it's recommended that you + should always call stopThread() with a decent timeout before deleting, + to avoid the thread being forcibly killed (which is a Bad Thing). */ - class JUCE_API JobSelector - { - public: - virtual ~JobSelector() {} - - /** Should return true if the specified thread matches your criteria for whatever - operation that this object is being used for. + virtual ~Thread(); - Any implementation of this method must be extremely fast and thread-safe! - */ - virtual bool isJobSuitable (ThreadPoolJob* job) = 0; - }; + /** Must be implemented to perform the thread's actual code. - /** Adds a job to the queue. + Remember that the thread must regularly check the threadShouldExit() + method whilst running, and if this returns true it should return from + the run() method as soon as possible to avoid being forcibly killed. - Once a job has been added, then the next time a thread is free, it will run - the job's ThreadPoolJob::runJob() method. Depending on the return value of the - runJob() method, the pool will either remove the job from the pool or add it to - the back of the queue to be run again. + @see threadShouldExit, startThread */ - void addJob (ThreadPoolJob* const job); + virtual void run() = 0; - /** Tries to remove a job from the pool. + // Thread control functions.. - If the job isn't yet running, this will simply remove it. If it is running, it - will wait for it to finish. + /** Starts the thread running. - If the timeout period expires before the job finishes running, then the job will be - left in the pool and this will return false. It returns true if the job is sucessfully - stopped and removed. + This will start the thread's run() method. + (if it's already started, startThread() won't do anything). - @param job the job to remove - @param interruptIfRunning if true, then if the job is currently busy, its - ThreadPoolJob::signalJobShouldExit() method will be called to try - to interrupt it. If false, then if the job will be allowed to run - until it stops normally (or the timeout expires) - @param timeOutMilliseconds the length of time this method should wait for the job to finish - before giving up and returning false + @see stopThread */ - bool removeJob (ThreadPoolJob* const job, - const bool interruptIfRunning, - const int timeOutMilliseconds); + void startThread() throw(); - /** Tries to remove all jobs from the pool. + /** Starts the thread with a given priority. - @param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit() - methods called to try to interrupt them - @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish - before giving up and returning false - @param deleteInactiveJobs if true, any jobs that aren't currently running will be deleted. If false, - they will simply be removed from the pool. Jobs that are already running when - this method is called can choose whether they should be deleted by - returning jobHasFinishedAndShouldBeDeleted from their runJob() method. - @param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which - jobs should be removed. If it is zero, all jobs are removed - @returns true if all jobs are successfully stopped and removed; false if the timeout period - expires while waiting for one or more jobs to stop - */ - bool removeAllJobs (const bool interruptRunningJobs, - const int timeOutMilliseconds, - const bool deleteInactiveJobs = false, - JobSelector* selectedJobsToRemove = 0); + Launches the thread with a given priority, where 0 = lowest, 10 = highest. + If the thread is already running, its priority will be changed. - /** Returns the number of jobs currently running or queued. + @see startThread, setPriority */ - int getNumJobs() const throw(); - - /** Returns one of the jobs in the queue. + void startThread (const int priority) throw(); - Note that this can be a very volatile list as jobs might be continuously getting shifted - around in the list, and this method may return 0 if the index is currently out-of-range. - */ - ThreadPoolJob* getJob (const int index) const throw(); + /** Attempts to stop the thread running. - /** Returns true if the given job is currently queued or running. + This method will cause the threadShouldExit() method to return true + and call notify() in case the thread is currently waiting. - @see isJobRunning() - */ - bool contains (const ThreadPoolJob* const job) const throw(); + Hopefully the thread will then respond to this by exiting cleanly, and + the stopThread method will wait for a given time-period for this to + happen. - /** Returns true if the given job is currently being run by a thread. + If the thread is stuck and fails to respond after the time-out, it gets + forcibly killed, which is a very bad thing to happen, as it could still + be holding locks, etc. which are needed by other parts of your program. + + @param timeOutMilliseconds The number of milliseconds to wait for the + thread to finish before killing it by force. A negative + value in here will wait forever. + @see signalThreadShouldExit, threadShouldExit, waitForThreadToExit, isThreadRunning */ - bool isJobRunning (const ThreadPoolJob* const job) const; + void stopThread (const int timeOutMilliseconds) throw(); - /** Waits until a job has finished running and has been removed from the pool. + /** Returns true if the thread is currently active */ + bool isThreadRunning() const throw(); - This will wait until the job is no longer in the pool - i.e. until its - runJob() method returns ThreadPoolJob::jobHasFinished. + /** Sets a flag to tell the thread it should stop. - If the timeout period expires before the job finishes, this will return false; - it returns true if the job has finished successfully. + Calling this means that the threadShouldExit() method will then return true. + The thread should be regularly checking this to see whether it should exit. + + @see threadShouldExit + @see waitForThreadToExit */ - bool waitForJobToFinish (const ThreadPoolJob* const job, - const int timeOutMilliseconds) const; + void signalThreadShouldExit() throw(); - /** Returns a list of the names of all the jobs currently running or queued. + /** Checks whether the thread has been told to stop running. - If onlyReturnActiveJobs is true, only the ones currently running are returned. + Threads need to check this regularly, and if it returns true, they should + return from their run() method at the first possible opportunity. + + @see signalThreadShouldExit */ - const StringArray getNamesOfAllJobs (const bool onlyReturnActiveJobs) const throw(); + inline bool threadShouldExit() const throw() { return threadShouldExit_; } - /** Changes the priority of all the threads. + /** Waits for the thread to stop. - This will call Thread::setPriority() for each thread in the pool. - May return false if for some reason the priority can't be changed. + This will waits until isThreadRunning() is false or until a timeout expires. + + @param timeOutMilliseconds the time to wait, in milliseconds. If this value + is less than zero, it will wait forever. + @returns true if the thread exits, or false if the timeout expires first. */ - bool setThreadPriorities (const int newPriority); + bool waitForThreadToExit (const int timeOutMilliseconds) const throw(); - juce_UseDebuggingNewOperator + /** Changes the thread's priority. + May return false if for some reason the priority can't be changed. -private: - const int numThreads, threadStopTimeout; - int priority; - Thread** threads; - VoidArray jobs; + @param priority the new priority, in the range 0 (lowest) to 10 (highest). A priority + of 5 is normal. + */ + bool setPriority (const int priority) throw(); - CriticalSection lock; - uint32 lastJobEndTime; - WaitableEvent jobFinishedSignal; + /** Changes the priority of the caller thread. - friend class ThreadPoolThread; - bool runNextJob(); + Similar to setPriority(), but this static method acts on the caller thread. + May return false if for some reason the priority can't be changed. - ThreadPool (const ThreadPool&); - const ThreadPool& operator= (const ThreadPool&); -}; + @see setPriority + */ + static bool setCurrentThreadPriority (const int priority) throw(); -#endif // __JUCE_THREADPOOL_JUCEHEADER__ -/********* End of inlined file: juce_ThreadPool.h *********/ + /** Sets the affinity mask for the thread. -#endif -#ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ + This will only have an effect next time the thread is started - i.e. if the + thread is already running when called, it'll have no effect. -/********* Start of inlined file: juce_TimeSliceThread.h *********/ -#ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ -#define __JUCE_TIMESLICETHREAD_JUCEHEADER__ + @see setCurrentThreadAffinityMask + */ + void setAffinityMask (const uint32 affinityMask) throw(); -/** - Used by the TimeSliceThread class. + /** Changes the affinity mask for the caller thread. - To register your class with a TimeSliceThread, derive from this class and - use the TimeSliceThread::addTimeSliceClient() method to add it to the list. + This will change the affinity mask for the thread that calls this static method. - Make sure you always call TimeSliceThread::removeTimeSliceClient() before - deleting your client! + @see setAffinityMask + */ + static void setCurrentThreadAffinityMask (const uint32 affinityMask) throw(); - @see TimeSliceThread -*/ -class JUCE_API TimeSliceClient -{ -public: - /** Destructor. */ - virtual ~TimeSliceClient() {} + // this can be called from any thread that needs to pause.. + static void JUCE_CALLTYPE sleep (int milliseconds) throw(); - /** Called back by a TimeSliceThread. + /** Yields the calling thread's current time-slot. */ + static void JUCE_CALLTYPE yield() throw(); - When you register this class with it, a TimeSliceThread will repeatedly call - this method. + /** Makes the thread wait for a notification. - The implementation of this method should use its time-slice to do something that's - quick - never block for longer than absolutely necessary. + This puts the thread to sleep until either the timeout period expires, or + another thread calls the notify() method to wake it up. - @returns Your method should return true if it needs more time, or false if it's - not too busy and doesn't need calling back urgently. If all the thread's - clients indicate that they're not busy, then it'll save CPU by sleeping for - up to half a second in between callbacks. You can force the TimeSliceThread - to wake up and poll again immediately by calling its notify() method. + @returns true if the event has been signalled, false if the timeout expires. */ - virtual bool useTimeSlice() = 0; -}; - -/** - A thread that keeps a list of clients, and calls each one in turn, giving them - all a chance to run some sort of short task. + bool wait (const int timeOutMilliseconds) const throw(); - @see TimeSliceClient, Thread -*/ -class JUCE_API TimeSliceThread : public Thread -{ -public: + /** Wakes up the thread. - /** - Creates a TimeSliceThread. + If the thread has called the wait() method, this will wake it up. - When first created, the thread is not running. Use the startThread() - method to start it. + @see wait */ - TimeSliceThread (const String& threadName); - - /** Destructor. + void notify() const throw(); - Deleting a Thread object that is running will only give the thread a - brief opportunity to stop itself cleanly, so it's recommended that you - should always call stopThread() with a decent timeout before deleting, - to avoid the thread being forcibly killed (which is a Bad Thing). + /** A value type used for thread IDs. + @see getCurrentThreadId(), getThreadId() */ - ~TimeSliceThread(); + typedef void* ThreadID; - /** Adds a client to the list. + /** Returns an id that identifies the caller thread. - The client's callbacks will start immediately (possibly before the method - has returned). + To find the ID of a particular thread object, use getThreadId(). + + @returns a unique identifier that identifies the calling thread. + @see getThreadId */ - void addTimeSliceClient (TimeSliceClient* const client); + static ThreadID getCurrentThreadId() throw(); - /** Removes a client from the list. + /** Finds the thread object that is currently running. - This method will make sure that all callbacks to the client have completely - finished before the method returns. + Note that the main UI thread (or other non-Juce threads) don't have a Thread + object associated with them, so this will return 0. */ - void removeTimeSliceClient (TimeSliceClient* const client); + static Thread* getCurrentThread() throw(); - /** Returns the number of registered clients. */ - int getNumClients() const throw(); + /** Returns the ID of this thread. - /** Returns one of the registered clients. */ - TimeSliceClient* getClient (const int index) const throw(); + That means the ID of this thread object - not of the thread that's calling the method. - /** @internal */ - void run(); + This can change when the thread is started and stopped, and will be invalid if the + thread's not actually running. - juce_UseDebuggingNewOperator + @see getCurrentThreadId + */ + ThreadID getThreadId() const throw(); -private: - CriticalSection callbackLock, listLock; - Array clients; - int index; - TimeSliceClient* clientBeingCalled; - bool clientsChanged; + /** Returns the name of the thread. - TimeSliceThread (const TimeSliceThread&); - const TimeSliceThread& operator= (const TimeSliceThread&); -}; + This is the name that gets set in the constructor. + */ + const String getThreadName() const throw() { return threadName_; } -#endif // __JUCE_TIMESLICETHREAD_JUCEHEADER__ -/********* End of inlined file: juce_TimeSliceThread.h *********/ + /** Returns the number of currently-running threads. -#endif -#ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ + @returns the number of Thread objects known to be currently running. + @see stopAllThreads + */ + static int getNumRunningThreads() throw(); -#endif + /** Tries to stop all currently-running threads. -#endif -/********* End of inlined file: juce_core_includes.h *********/ + This will attempt to stop all the threads known to be running at the moment. + */ + static void stopAllThreads (const int timeoutInMillisecs) throw(); -// if you're compiling a command-line app, you might want to just include the core headers, -// so you can set this macro before including juce.h -#if ! JUCE_ONLY_BUILD_CORE_LIBRARY + juce_UseDebuggingNewOperator -/********* Start of inlined file: juce_app_includes.h *********/ -#ifndef __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ -#define __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ +private: + const String threadName_; + void* volatile threadHandle_; + CriticalSection startStopLock; + WaitableEvent startSuspensionEvent_, defaultEvent_; -#ifndef __JUCE_APPLICATION_JUCEHEADER__ + int threadPriority_; + ThreadID threadId_; + uint32 affinityMask_; + bool volatile threadShouldExit_; -/********* Start of inlined file: juce_Application.h *********/ -#ifndef __JUCE_APPLICATION_JUCEHEADER__ -#define __JUCE_APPLICATION_JUCEHEADER__ + friend void JUCE_API juce_threadEntryPoint (void*); + static void threadEntryPoint (Thread* thread) throw(); -/********* Start of inlined file: juce_ApplicationCommandTarget.h *********/ -#ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ -#define __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ + Thread (const Thread&); + const Thread& operator= (const Thread&); +}; -/********* Start of inlined file: juce_Component.h *********/ -#ifndef __JUCE_COMPONENT_JUCEHEADER__ -#define __JUCE_COMPONENT_JUCEHEADER__ +#endif // __JUCE_THREAD_JUCEHEADER__ +/********* End of inlined file: juce_Thread.h *********/ -/********* Start of inlined file: juce_MouseCursor.h *********/ -#ifndef __JUCE_MOUSECURSOR_JUCEHEADER__ -#define __JUCE_MOUSECURSOR_JUCEHEADER__ +/** + A critical section that allows multiple simultaneous readers. -class Image; -class RefCountedMouseCursor; -class ComponentPeer; -class Component; + Features of this type of lock are: -/** - Represents a mouse cursor image. + - Multiple readers can hold the lock at the same time, but only one writer + can hold it at once. + - Writers trying to gain the lock will be blocked until all readers and writers + have released it + - Readers trying to gain the lock while a writer is waiting to acquire it will be + blocked until the writer has obtained and released it + - If a thread already has a read lock and tries to obtain a write lock, it will succeed if + there are no other readers + - If a thread already has the write lock and tries to obtain a read lock, this will succeed. + - Recursive locking is supported. - This object can either be used to represent one of the standard mouse - cursor shapes, or a custom one generated from an image. + @see ScopedReadLock, ScopedWriteLock, CriticalSection */ -class JUCE_API MouseCursor +class JUCE_API ReadWriteLock { public: - /** The set of available standard mouse cursors. */ - enum StandardCursorType - { - NoCursor = 0, /**< An invisible cursor. */ - NormalCursor, /**< The stardard arrow cursor. */ - - WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */ - IBeamCursor, /**< A vertical I-beam for positioning within text. */ - CrosshairCursor, /**< A pair of crosshairs. */ - CopyingCursor, /**< The normal arrow cursor, but with a "+" on it to indicate - that you're dragging a copy of something. */ - - PointingHandCursor, /**< A hand with a pointing finger, for clicking on web-links. */ - DraggingHandCursor, /**< An open flat hand for dragging heavy objects around. */ - - LeftRightResizeCursor, /**< An arrow pointing left and right. */ - UpDownResizeCursor, /**< an arrow pointing up and down. */ - UpDownLeftRightResizeCursor, /**< An arrow pointing up, down, left and right. */ + /** + Creates a ReadWriteLock object. + */ + ReadWriteLock() throw(); - TopEdgeResizeCursor, /**< A platform-specific cursor for resizing the top-edge of a window. */ - BottomEdgeResizeCursor, /**< A platform-specific cursor for resizing the bottom-edge of a window. */ - LeftEdgeResizeCursor, /**< A platform-specific cursor for resizing the left-edge of a window. */ - RightEdgeResizeCursor, /**< A platform-specific cursor for resizing the right-edge of a window. */ - TopLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the top-left-corner of a window. */ - TopRightCornerResizeCursor, /**< A platform-specific cursor for resizing the top-right-corner of a window. */ - BottomLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the bottom-left-corner of a window. */ - BottomRightCornerResizeCursor /**< A platform-specific cursor for resizing the bottom-right-corner of a window. */ - }; + /** Destructor. - /** Creates the standard arrow cursor. */ - MouseCursor() throw(); + If the object is deleted whilst locked, any subsequent behaviour + is unpredictable. + */ + ~ReadWriteLock() throw(); - /** Creates one of the standard mouse cursor */ - MouseCursor (const StandardCursorType type) throw(); + /** Locks this object for reading. - /** Creates a custom cursor from an image. + Multiple threads can simulaneously lock the object for reading, but if another + thread has it locked for writing, then this will block until it releases the + lock. - @param image the image to use for the cursor - if this is bigger than the - system can manage, it might get scaled down first, and might - also have to be turned to black-and-white if it can't do colour - cursors. - @param hotSpotX the x position of the cursor's hotspot within the image - @param hotSpotY the y position of the cursor's hotspot within the image + @see exitRead, ScopedReadLock */ - MouseCursor (Image& image, - const int hotSpotX, - const int hotSpotY) throw(); - - /** Creates a copy of another cursor object. */ - MouseCursor (const MouseCursor& other) throw(); + void enterRead() const throw(); - /** Copies this cursor from another object. */ - const MouseCursor& operator= (const MouseCursor& other) throw(); + /** Releases the read-lock. - /** Destructor. */ - ~MouseCursor() throw(); + If the caller thread hasn't got the lock, this can have unpredictable results. - /** Checks whether two mouse cursors are the same. + If the enterRead() method has been called multiple times by the thread, each + call must be matched by a call to exitRead() before other threads will be allowed + to take over the lock. - For custom cursors, two cursors created from the same image won't be - recognised as the same, only MouseCursor objects that have been - copied from the same object. + @see enterRead, ScopedReadLock */ - bool operator== (const MouseCursor& other) const throw(); + void exitRead() const throw(); - /** Checks whether two mouse cursors are the same. + /** Locks this object for writing. - For custom cursors, two cursors created from the same image won't be - recognised as the same, only MouseCursor objects that have been - copied from the same object. - */ - bool operator!= (const MouseCursor& other) const throw(); + This will block until any other threads that have it locked for reading or + writing have released their lock. - /** Makes the system show its default 'busy' cursor. + @see exitWrite, ScopedWriteLock + */ + void enterWrite() const throw(); - This will turn the system cursor to an hourglass or spinning beachball - until the next time the mouse is moved, or hideWaitCursor() is called. + /** Tries to lock this object for writing. - This is handy if the message loop is about to block for a couple of - seconds while busy and you want to give the user feedback about this. + This is like enterWrite(), but doesn't block - it returns true if it manages + to obtain the lock. - @see MessageManager::setTimeBeforeShowingWaitCursor + @see enterWrite */ - static void showWaitCursor() throw(); + bool tryEnterWrite() const throw(); - /** If showWaitCursor has been called, this will return the mouse to its - normal state. + /** Releases the write-lock. - This will look at what component is under the mouse, and update the - cursor to be the correct one for that component. + If the caller thread hasn't got the lock, this can have unpredictable results. - @see showWaitCursor + If the enterWrite() method has been called multiple times by the thread, each + call must be matched by a call to exit() before other threads will be allowed + to take over the lock. + + @see enterWrite, ScopedWriteLock */ - static void hideWaitCursor() throw(); + void exitWrite() const throw(); juce_UseDebuggingNewOperator private: - RefCountedMouseCursor* cursorHandle; - friend class Component; - - void showInWindow (ComponentPeer* window) const throw(); - void showInAllWindows() const throw(); + CriticalSection accessLock; + WaitableEvent waitEvent; + mutable int numWaitingWriters, numWriters; + mutable Thread::ThreadID writerThreadId; + mutable Array readerThreads; - void* getHandle() const throw(); + ReadWriteLock (const ReadWriteLock&); + const ReadWriteLock& operator= (const ReadWriteLock&); }; -#endif // __JUCE_MOUSECURSOR_JUCEHEADER__ -/********* End of inlined file: juce_MouseCursor.h *********/ - -/********* Start of inlined file: juce_MouseListener.h *********/ -#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__ -#define __JUCE_MOUSELISTENER_JUCEHEADER__ +#endif // __JUCE_READWRITELOCK_JUCEHEADER__ +/********* End of inlined file: juce_ReadWriteLock.h *********/ -/********* Start of inlined file: juce_MouseEvent.h *********/ -#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__ -#define __JUCE_MOUSEEVENT_JUCEHEADER__ +#endif +#ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ -class Component; +#endif +#ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ -/********* Start of inlined file: juce_ModifierKeys.h *********/ -#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ -#define __JUCE_MODIFIERKEYS_JUCEHEADER__ +/********* Start of inlined file: juce_ScopedReadLock.h *********/ +#ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ +#define __JUCE_SCOPEDREADLOCK_JUCEHEADER__ /** - Represents the state of the mouse buttons and modifier keys. - - This is used both by mouse events and by KeyPress objects to describe - the state of keys such as shift, control, alt, etc. + Automatically locks and unlocks a ReadWriteLock object. - @see KeyPress, MouseEvent::mods -*/ -class JUCE_API ModifierKeys -{ -public: + Use one of these as a local variable to control access to a ReadWriteLock. - /** Creates a ModifierKeys object from a raw set of flags. + e.g. @code - @param flags to represent the keys that are down - @see shiftModifier, ctrlModifier, altModifier, leftButtonModifier, - rightButtonModifier, commandModifier, popupMenuClickModifier - */ - ModifierKeys (const int flags = 0) throw(); + ReadWriteLock myLock; - /** Creates a copy of another object. */ - ModifierKeys (const ModifierKeys& other) throw(); + for (;;) + { + const ScopedReadLock myScopedLock (myLock); + // myLock is now locked - /** Copies this object from another one. */ - const ModifierKeys& operator= (const ModifierKeys& other) throw(); + ...do some stuff... - /** Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux). + // myLock gets unlocked here. + } + @endcode - This is a platform-agnostic way of checking for the operating system's - preferred command-key modifier - so on the Mac it tests for the Apple key, on - Windows/Linux, it's actually checking for the CTRL key. - */ - inline bool isCommandDown() const throw() { return (flags & commandModifier) != 0; } + @see ReadWriteLock, ScopedWriteLock +*/ +class JUCE_API ScopedReadLock +{ +public: - /** Checks whether the user is trying to launch a pop-up menu. + /** Creates a ScopedReadLock. - This checks for platform-specific modifiers that might indicate that the user - is following the operating system's normal method of showing a pop-up menu. + As soon as it is created, this will call ReadWriteLock::enterRead(), and + when the ScopedReadLock object is deleted, the ReadWriteLock will + be unlocked. - So on Windows/Linux, this method is really testing for a right-click. - On the Mac, it tests for either the CTRL key being down, or a right-click. + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! Best just to use it + as a local stack object, rather than creating one with the new() operator. */ - inline bool isPopupMenu() const throw() { return (flags & popupMenuClickModifier) != 0; } + inline ScopedReadLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterRead(); } - /** Checks whether the flag is set for the left mouse-button. */ - inline bool isLeftButtonDown() const throw() { return (flags & leftButtonModifier) != 0; } + /** Destructor. - /** Checks whether the flag is set for the right mouse-button. + The ReadWriteLock's exitRead() method will be called when the destructor is called. - Note that for detecting popup-menu clicks, you should be using isPopupMenu() instead, as - this is platform-independent (and makes your code more explanatory too). + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! */ - inline bool isRightButtonDown() const throw() { return (flags & rightButtonModifier) != 0; } + inline ~ScopedReadLock() throw() { lock_.exitRead(); } - inline bool isMiddleButtonDown() const throw() { return (flags & middleButtonModifier) != 0; } +private: - /** Tests for any of the mouse-button flags. */ - inline bool isAnyMouseButtonDown() const throw() { return (flags & allMouseButtonModifiers) != 0; } + const ReadWriteLock& lock_; - /** Tests for any of the modifier key flags. */ - inline bool isAnyModifierKeyDown() const throw() { return (flags & (shiftModifier | ctrlModifier | altModifier | commandModifier)) != 0; } + ScopedReadLock (const ScopedReadLock&); + const ScopedReadLock& operator= (const ScopedReadLock&); +}; - /** Checks whether the shift key's flag is set. */ - inline bool isShiftDown() const throw() { return (flags & shiftModifier) != 0; } +#endif // __JUCE_SCOPEDREADLOCK_JUCEHEADER__ +/********* End of inlined file: juce_ScopedReadLock.h *********/ - /** Checks whether the CTRL key's flag is set. +#endif +#ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ - Remember that it's better to use the platform-agnostic routines to test for command-key and - popup-menu modifiers. +/********* Start of inlined file: juce_ScopedTryLock.h *********/ +#ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ +#define __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ - @see isCommandDown, isPopupMenu - */ - inline bool isCtrlDown() const throw() { return (flags & ctrlModifier) != 0; } +/** + Automatically tries to lock and unlock a CriticalSection object. - /** Checks whether the shift key's flag is set. */ - inline bool isAltDown() const throw() { return (flags & altModifier) != 0; } + Use one of these as a local variable to control access to a CriticalSection. - /** Flags that represent the different keys. */ - enum Flags + e.g. @code + + CriticalSection myCriticalSection; + + for (;;) { - /** Shift key flag. */ - shiftModifier = 1, + const ScopedTryLock myScopedTryLock (myCriticalSection); - /** CTRL key flag. */ - ctrlModifier = 2, + // Unlike using a ScopedLock, this may fail to actually get the lock, so you + // should test this with the isLocked() method before doing your thread-unsafe + // action.. + if (myScopedTryLock.isLocked()) + { + ...do some stuff... + } + else + { + ..our attempt at locking failed because another thread had already locked it.. + } - /** ALT key flag. */ - altModifier = 4, + // myCriticalSection gets unlocked here (if it was locked) + } + @endcode - /** Left mouse button flag. */ - leftButtonModifier = 16, + @see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock +*/ +class JUCE_API ScopedTryLock +{ +public: - /** Right mouse button flag. */ - rightButtonModifier = 32, + /** Creates a ScopedTryLock. - /** Middle mouse button flag. */ - middleButtonModifier = 64, + As soon as it is created, this will try to lock the CriticalSection, and + when the ScopedTryLock object is deleted, the CriticalSection will + be unlocked if the lock was successful. -#if JUCE_MAC - /** Command key flag - on windows this is the same as the CTRL key flag. */ - commandModifier = 8, + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! Best just to use it + as a local stack object, rather than creating one with the new() operator. + */ + inline ScopedTryLock (const CriticalSection& lock) throw() : lock_ (lock), lockWasSuccessful (lock.tryEnter()) {} - /** Popup menu flag - on windows this is the same as rightButtonModifier, on the - Mac it's the same as (rightButtonModifier | ctrlModifier). */ - popupMenuClickModifier = rightButtonModifier | ctrlModifier, -#else - /** Command key flag - on windows this is the same as the CTRL key flag. */ - commandModifier = ctrlModifier, + /** Destructor. - /** Popup menu flag - on windows this is the same as rightButtonModifier, on the - Mac it's the same as (rightButtonModifier | ctrlModifier). */ - popupMenuClickModifier = rightButtonModifier, -#endif + The CriticalSection will be unlocked (if locked) when the destructor is called. - /** Represents a combination of all the shift, alt, ctrl and command key modifiers. */ - allKeyboardModifiers = shiftModifier | ctrlModifier | altModifier | commandModifier, + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! + */ + inline ~ScopedTryLock() throw() { if (lockWasSuccessful) lock_.exit(); } - /** Represents a combination of all the mouse buttons at once. */ - allMouseButtonModifiers = leftButtonModifier | rightButtonModifier | middleButtonModifier, - }; + /** Lock state - /** Returns the raw flags for direct testing. */ - inline int getRawFlags() const throw() { return flags; } + @return True if the CriticalSection is locked. + */ + bool isLocked() const throw() { return lockWasSuccessful; } - /** Tests a combination of flags and returns true if any of them are set. */ - inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } +private: - /** Creates a ModifierKeys object to represent the last-known state of the - keyboard and mouse buttons. + const CriticalSection& lock_; + const bool lockWasSuccessful; - @see getCurrentModifiersRealtime - */ - static const ModifierKeys getCurrentModifiers() throw(); + ScopedTryLock (const ScopedTryLock&); + const ScopedTryLock& operator= (const ScopedTryLock&); +}; - /** Creates a ModifierKeys object to represent the current state of the - keyboard and mouse buttons. +#endif // __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ +/********* End of inlined file: juce_ScopedTryLock.h *********/ - This isn't often needed and isn't recommended, but will actively check all the - mouse and key states rather than just returning their last-known state like - getCurrentModifiers() does. +#endif +#ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ - This is only needed in special circumstances for up-to-date modifier information - at times when the app's event loop isn't running normally. - */ - static const ModifierKeys getCurrentModifiersRealtime() throw(); +/********* Start of inlined file: juce_ScopedWriteLock.h *********/ +#ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ +#define __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ -private: +/** + Automatically locks and unlocks a ReadWriteLock object. - int flags; + Use one of these as a local variable to control access to a ReadWriteLock. - static int currentModifierFlags; + e.g. @code - friend class ComponentPeer; - static void updateCurrentModifiers() throw(); -}; + ReadWriteLock myLock; -#endif // __JUCE_MODIFIERKEYS_JUCEHEADER__ -/********* End of inlined file: juce_ModifierKeys.h *********/ + for (;;) + { + const ScopedWriteLock myScopedLock (myLock); + // myLock is now locked -/** - Contains position and status information about a mouse event. + ...do some stuff... - @see MouseListener, Component::mouseMove, Component::mouseEnter, Component::mouseExit, - Component::mouseDown, Component::mouseUp, Component::mouseDrag + // myLock gets unlocked here. + } + @endcode + + @see ReadWriteLock, ScopedReadLock */ -class JUCE_API MouseEvent +class JUCE_API ScopedWriteLock { public: - /** Creates a MouseEvent. + /** Creates a ScopedWriteLock. - Normally an application will never need to use this. + As soon as it is created, this will call ReadWriteLock::enterWrite(), and + when the ScopedWriteLock object is deleted, the ReadWriteLock will + be unlocked. - @param x the x position of the mouse, relative to the component that is passed-in - @param y the y position of the mouse, relative to the component that is passed-in - @param modifiers the key modifiers at the time of the event - @param originator the component that the mouse event applies to - @param eventTime the time the event happened - @param mouseDownX the x position of the corresponding mouse-down event (relative to the component that is passed-in). - If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be - the same as the current mouse-x position. - @param mouseDownY the y position of the corresponding mouse-down event (relative to the component that is passed-in) - If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be - the same as the current mouse-y position. - @param mouseDownTime the time at which the corresponding mouse-down event happened - If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be - the same as the current mouse-event time. - @param numberOfClicks how many clicks, e.g. a double-click event will be 2, a triple-click will be 3, etc - @param mouseWasDragged whether the mouse has been dragged significantly since the previous mouse-down + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! Best just to use it + as a local stack object, rather than creating one with the new() operator. */ - MouseEvent (const int x, const int y, - const ModifierKeys& modifiers, - Component* const originator, - const Time& eventTime, - const int mouseDownX, - const int mouseDownY, - const Time& mouseDownTime, - const int numberOfClicks, - const bool mouseWasDragged) throw(); + inline ScopedWriteLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterWrite(); } - /** Destructor. */ - ~MouseEvent() throw(); + /** Destructor. - /** The x-position of the mouse when the event occurred. + The ReadWriteLock's exitWrite() method will be called when the destructor is called. - This value is relative to the top-left of the component to which the - event applies (as indicated by the MouseEvent::eventComponent field). + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! */ - int x; + inline ~ScopedWriteLock() throw() { lock_.exitWrite(); } - /** The y-position of the mouse when the event occurred. +private: - This value is relative to the top-left of the component to which the - event applies (as indicated by the MouseEvent::eventComponent field). - */ - int y; + const ReadWriteLock& lock_; - /** The key modifiers associated with the event. + ScopedWriteLock (const ScopedWriteLock&); + const ScopedWriteLock& operator= (const ScopedWriteLock&); +}; - This will let you find out which mouse buttons were down, as well as which - modifier keys were held down. +#endif // __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ +/********* End of inlined file: juce_ScopedWriteLock.h *********/ - When used for mouse-up events, this will indicate the state of the mouse buttons - just before they were released, so that you can tell which button they let go of. - */ - ModifierKeys mods; +#endif +#ifndef __JUCE_THREAD_JUCEHEADER__ - /** The component that this event applies to. +#endif +#ifndef __JUCE_THREADPOOL_JUCEHEADER__ - This is usually the component that the mouse was over at the time, but for mouse-drag - events the mouse could actually be over a different component and the events are - still sent to the component that the button was originally pressed on. +/********* Start of inlined file: juce_ThreadPool.h *********/ +#ifndef __JUCE_THREADPOOL_JUCEHEADER__ +#define __JUCE_THREADPOOL_JUCEHEADER__ - The x and y member variables are relative to this component's position. +class ThreadPool; +class ThreadPoolThread; - If you use getEventRelativeTo() to retarget this object to be relative to a different - component, this pointer will be updated, but originalComponent remains unchanged. +/** + A task that is executed by a ThreadPool object. - @see originalComponent + A ThreadPool keeps a list of ThreadPoolJob objects which are executed by + its threads. + + The runJob() method needs to be implemented to do the task, and if the code that + does the work takes a significant time to run, it must keep checking the shouldExit() + method to see if something is trying to interrupt the job. If shouldExit() returns + true, the runJob() method must return immediately. + + @see ThreadPool, Thread +*/ +class JUCE_API ThreadPoolJob +{ +public: + + /** Creates a thread pool job object. + + After creating your job, add it to a thread pool with ThreadPool::addJob(). */ - Component* eventComponent; + ThreadPoolJob (const String& name); - /** The component that the event first occurred on. + /** Destructor. */ + virtual ~ThreadPoolJob(); - If you use getEventRelativeTo() to retarget this object to be relative to a different - component, this value remains unchanged to indicate the first component that received it. + /** Returns the name of this job. + @see setJobName + */ + const String getJobName() const throw(); - @see eventComponent + /** Changes the job's name. + @see getJobName */ - Component* originalComponent; + void setJobName (const String& newName) throw(); - /** The time that this mouse-event occurred. + /** These are the values that can be returned by the runJob() method. */ - Time eventTime; + enum JobStatus + { + jobHasFinished = 0, /**< indicates that the job has finished and can be + removed from the pool. */ - /** Returns the x co-ordinate of the last place that a mouse was pressed. + jobHasFinishedAndShouldBeDeleted, /**< indicates that the job has finished and that it + should be automatically deleted by the pool. */ - The co-ordinate is relative to the component specified in MouseEvent::component. + jobNeedsRunningAgain /**< indicates that the job would like to be called + again when a thread is free. */ + }; - @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked - */ - int getMouseDownX() const throw(); + /** Peforms the actual work that this job needs to do. - /** Returns the y co-ordinate of the last place that a mouse was pressed. + Your subclass must implement this method, in which is does its work. - The co-ordinate is relative to the component specified in MouseEvent::component. + If the code in this method takes a significant time to run, it must repeatedly check + the shouldExit() method to see if something is trying to interrupt the job. + If shouldExit() ever returns true, the runJob() method must return immediately. - @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked + If this method returns jobHasFinished, then the job will be removed from the pool + immediately. If it returns jobNeedsRunningAgain, then the job will be left in the + pool and will get a chance to run again as soon as a thread is free. + + @see shouldExit() */ - int getMouseDownY() const throw(); + virtual JobStatus runJob() = 0; - /** Returns the straight-line distance between where the mouse is now and where it - was the last time the button was pressed. + /** Returns true if this job is currently running its runJob() method. */ + bool isRunning() const throw() { return isActive; } - This is quite handy for things like deciding whether the user has moved far enough - for it to be considered a drag operation. + /** Returns true if something is trying to interrupt this job and make it stop. - @see getDistanceFromDragStartX + Your runJob() method must call this whenever it gets a chance, and if it ever + returns true, the runJob() method must return immediately. + + @see signalJobShouldExit() */ - int getDistanceFromDragStart() const throw(); + bool shouldExit() const throw() { return shouldStop; } - /** Returns the difference between the mouse's current x postion and where it was - when the button was last pressed. + /** Calling this will cause the shouldExit() method to return true, and the job + should (if it's been implemented correctly) stop as soon as possible. - @see getDistanceFromDragStart + @see shouldExit() */ - int getDistanceFromDragStartX() const throw(); + void signalJobShouldExit() throw(); - /** Returns the difference between the mouse's current y postion and where it was - when the button was last pressed. + juce_UseDebuggingNewOperator - @see getDistanceFromDragStart - */ - int getDistanceFromDragStartY() const throw(); +private: + friend class ThreadPool; + friend class ThreadPoolThread; + String jobName; + ThreadPool* pool; + bool shouldStop, isActive, shouldBeDeleted; - /** Returns true if the mouse has just been clicked. + ThreadPoolJob (const ThreadPoolJob&); + const ThreadPoolJob& operator= (const ThreadPoolJob&); +}; - Used in either your mouseUp() or mouseDrag() methods, this will tell you whether - the user has dragged the mouse more than a few pixels from the place where the - mouse-down occurred. +/** + A set of threads that will run a list of jobs. - Once they have dragged it far enough for this method to return false, it will continue - to return false until the mouse-up, even if they move the mouse back to the same - position where they originally pressed it. This means that it's very handy for - objects that can either be clicked on or dragged, as you can use it in the mouseDrag() - callback to ignore any small movements they might make while clicking. + When a ThreadPoolJob object is added to the ThreadPool's list, its run() method + will be called by the next pooled thread that becomes free. - @returns true if the mouse wasn't dragged by more than a few pixels between - the last time the button was pressed and released. - */ - bool mouseWasClicked() const throw(); + @see ThreadPoolJob, Thread +*/ +class JUCE_API ThreadPool +{ +public: - /** For a click event, the number of times the mouse was clicked in succession. + /** Creates a thread pool. - So for example a double-click event will return 2, a triple-click 3, etc. + Once you've created a pool, you can give it some things to do with the addJob() + method. + + @param numberOfThreads the maximum number of actual threads to run. + @param startThreadsOnlyWhenNeeded if this is true, then no threads will be started + until there are some jobs to run. If false, then + all the threads will be fired-up immediately so that + they're ready for action + @param stopThreadsWhenNotUsedTimeoutMs if this timeout is > 0, then if any threads have been + inactive for this length of time, they will automatically + be stopped until more jobs come along and they're needed */ - int getNumberOfClicks() const throw() { return numberOfClicks; } + ThreadPool (const int numberOfThreads, + const bool startThreadsOnlyWhenNeeded = true, + const int stopThreadsWhenNotUsedTimeoutMs = 5000); - /** Returns the time that the mouse button has been held down for. + /** Destructor. - If called from a mouseDrag or mouseUp callback, this will return the - number of milliseconds since the corresponding mouseDown event occurred. - If called in other contexts, e.g. a mouseMove, then the returned value - may be 0 or an undefined value. + This will attempt to remove all the jobs before deleting, but if you want to + specify a timeout, you should call removeAllJobs() explicitly before deleting + the pool. */ - int getLengthOfMousePress() const throw(); + ~ThreadPool(); - /** Returns the mouse x position of this event, in global screen co-ordinates. + /** A callback class used when you need to select which ThreadPoolJob objects are suitable + for some kind of operation. + @see ThreadPool::removeAllJobs + */ + class JUCE_API JobSelector + { + public: + virtual ~JobSelector() {} - The co-ordinates are relative to the top-left of the main monitor. + /** Should return true if the specified thread matches your criteria for whatever + operation that this object is being used for. - @see getMouseDownScreenX, Desktop::getMousePosition + Any implementation of this method must be extremely fast and thread-safe! + */ + virtual bool isJobSuitable (ThreadPoolJob* job) = 0; + }; + + /** Adds a job to the queue. + + Once a job has been added, then the next time a thread is free, it will run + the job's ThreadPoolJob::runJob() method. Depending on the return value of the + runJob() method, the pool will either remove the job from the pool or add it to + the back of the queue to be run again. */ - int getScreenX() const throw(); + void addJob (ThreadPoolJob* const job); - /** Returns the mouse y position of this event, in global screen co-ordinates. + /** Tries to remove a job from the pool. - The co-ordinates are relative to the top-left of the main monitor. + If the job isn't yet running, this will simply remove it. If it is running, it + will wait for it to finish. - @see getMouseDownScreenY, Desktop::getMousePosition - */ - int getScreenY() const throw(); + If the timeout period expires before the job finishes running, then the job will be + left in the pool and this will return false. It returns true if the job is sucessfully + stopped and removed. - /** Returns the x co-ordinate at which the mouse button was last pressed. + @param job the job to remove + @param interruptIfRunning if true, then if the job is currently busy, its + ThreadPoolJob::signalJobShouldExit() method will be called to try + to interrupt it. If false, then if the job will be allowed to run + until it stops normally (or the timeout expires) + @param timeOutMilliseconds the length of time this method should wait for the job to finish + before giving up and returning false + */ + bool removeJob (ThreadPoolJob* const job, + const bool interruptIfRunning, + const int timeOutMilliseconds); - The co-ordinates are relative to the top-left of the main monitor. + /** Tries to remove all jobs from the pool. - @see getScreenX, Desktop::getMousePosition + @param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit() + methods called to try to interrupt them + @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish + before giving up and returning false + @param deleteInactiveJobs if true, any jobs that aren't currently running will be deleted. If false, + they will simply be removed from the pool. Jobs that are already running when + this method is called can choose whether they should be deleted by + returning jobHasFinishedAndShouldBeDeleted from their runJob() method. + @param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which + jobs should be removed. If it is zero, all jobs are removed + @returns true if all jobs are successfully stopped and removed; false if the timeout period + expires while waiting for one or more jobs to stop */ - int getMouseDownScreenX() const throw(); + bool removeAllJobs (const bool interruptRunningJobs, + const int timeOutMilliseconds, + const bool deleteInactiveJobs = false, + JobSelector* selectedJobsToRemove = 0); - /** Returns the y co-ordinate at which the mouse button was last pressed. + /** Returns the number of jobs currently running or queued. + */ + int getNumJobs() const throw(); - The co-ordinates are relative to the top-left of the main monitor. + /** Returns one of the jobs in the queue. - @see getScreenY, Desktop::getMousePosition + Note that this can be a very volatile list as jobs might be continuously getting shifted + around in the list, and this method may return 0 if the index is currently out-of-range. */ - int getMouseDownScreenY() const throw(); + ThreadPoolJob* getJob (const int index) const throw(); - /** Creates a version of this event that is relative to a different component. + /** Returns true if the given job is currently queued or running. - The x and y positions of the event that is returned will have been - adjusted to be relative to the new component. + @see isJobRunning() */ - const MouseEvent getEventRelativeTo (Component* const otherComponent) const throw(); + bool contains (const ThreadPoolJob* const job) const throw(); - /** Changes the application-wide setting for the double-click time limit. + /** Returns true if the given job is currently being run by a thread. + */ + bool isJobRunning (const ThreadPoolJob* const job) const; - This is the maximum length of time between mouse-clicks for it to be - considered a double-click. It's used by the Component class. + /** Waits until a job has finished running and has been removed from the pool. - @see getDoubleClickTimeout, MouseListener::mouseDoubleClick + This will wait until the job is no longer in the pool - i.e. until its + runJob() method returns ThreadPoolJob::jobHasFinished. + + If the timeout period expires before the job finishes, this will return false; + it returns true if the job has finished successfully. */ - static void setDoubleClickTimeout (const int timeOutMilliseconds) throw(); + bool waitForJobToFinish (const ThreadPoolJob* const job, + const int timeOutMilliseconds) const; - /** Returns the application-wide setting for the double-click time limit. + /** Returns a list of the names of all the jobs currently running or queued. - This is the maximum length of time between mouse-clicks for it to be - considered a double-click. It's used by the Component class. + If onlyReturnActiveJobs is true, only the ones currently running are returned. + */ + const StringArray getNamesOfAllJobs (const bool onlyReturnActiveJobs) const throw(); - @see setDoubleClickTimeout, MouseListener::mouseDoubleClick + /** Changes the priority of all the threads. + + This will call Thread::setPriority() for each thread in the pool. + May return false if for some reason the priority can't be changed. */ - static int getDoubleClickTimeout() throw(); + bool setThreadPriorities (const int newPriority); juce_UseDebuggingNewOperator private: - int mouseDownX, mouseDownY; - Time mouseDownTime; - int numberOfClicks; - bool wasMovedSinceMouseDown; -}; - -#endif // __JUCE_MOUSEEVENT_JUCEHEADER__ -/********* End of inlined file: juce_MouseEvent.h *********/ + const int numThreads, threadStopTimeout; + int priority; + HeapBlock threads; + VoidArray jobs; + + CriticalSection lock; + uint32 lastJobEndTime; + WaitableEvent jobFinishedSignal; + + friend class ThreadPoolThread; + bool runNextJob(); + + ThreadPool (const ThreadPool&); + const ThreadPool& operator= (const ThreadPool&); +}; + +#endif // __JUCE_THREADPOOL_JUCEHEADER__ +/********* End of inlined file: juce_ThreadPool.h *********/ + +#endif +#ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ + +/********* Start of inlined file: juce_TimeSliceThread.h *********/ +#ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ +#define __JUCE_TIMESLICETHREAD_JUCEHEADER__ /** - A MouseListener can be registered with a component to receive callbacks - about mouse events that happen to that component. + Used by the TimeSliceThread class. - @see Component::addMouseListener, Component::removeMouseListener + To register your class with a TimeSliceThread, derive from this class and + use the TimeSliceThread::addTimeSliceClient() method to add it to the list. + + Make sure you always call TimeSliceThread::removeTimeSliceClient() before + deleting your client! + + @see TimeSliceThread */ -class JUCE_API MouseListener +class JUCE_API TimeSliceClient { public: /** Destructor. */ - virtual ~MouseListener() {} + virtual ~TimeSliceClient() {} - /** Called when the mouse moves inside a component. + /** Called back by a TimeSliceThread. - If the mouse button isn't pressed and the mouse moves over a component, - this will be called to let the component react to this. + When you register this class with it, a TimeSliceThread will repeatedly call + this method. - A component will always get a mouseEnter callback before a mouseMove. + The implementation of this method should use its time-slice to do something that's + quick - never block for longer than absolutely necessary. - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseEnter, mouseExit, mouseDrag, contains + @returns Your method should return true if it needs more time, or false if it's + not too busy and doesn't need calling back urgently. If all the thread's + clients indicate that they're not busy, then it'll save CPU by sleeping for + up to half a second in between callbacks. You can force the TimeSliceThread + to wake up and poll again immediately by calling its notify() method. */ - virtual void mouseMove (const MouseEvent& e); + virtual bool useTimeSlice() = 0; +}; - /** Called when the mouse first enters a component. +/** + A thread that keeps a list of clients, and calls each one in turn, giving them + all a chance to run some sort of short task. - If the mouse button isn't pressed and the mouse moves into a component, - this will be called to let the component react to this. + @see TimeSliceClient, Thread +*/ +class JUCE_API TimeSliceThread : public Thread +{ +public: - When the mouse button is pressed and held down while being moved in - or out of a component, no mouseEnter or mouseExit callbacks are made - only - mouseDrag messages are sent to the component that the mouse was originally - clicked on, until the button is released. + /** + Creates a TimeSliceThread. - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseExit, mouseDrag, mouseMove, contains + When first created, the thread is not running. Use the startThread() + method to start it. */ - virtual void mouseEnter (const MouseEvent& e); - - /** Called when the mouse moves out of a component. - - This will be called when the mouse moves off the edge of this - component. + TimeSliceThread (const String& threadName); - If the mouse button was pressed, and it was then dragged off the - edge of the component and released, then this callback will happen - when the button is released, after the mouseUp callback. + /** Destructor. - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseEnter, mouseDrag, mouseMove, contains + Deleting a Thread object that is running will only give the thread a + brief opportunity to stop itself cleanly, so it's recommended that you + should always call stopThread() with a decent timeout before deleting, + to avoid the thread being forcibly killed (which is a Bad Thing). */ - virtual void mouseExit (const MouseEvent& e); + ~TimeSliceThread(); - /** Called when a mouse button is pressed. + /** Adds a client to the list. - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. + The client's callbacks will start immediately (possibly before the method + has returned). + */ + void addTimeSliceClient (TimeSliceClient* const client); - Once a button is held down, the mouseDrag method will be called when the - mouse moves, until the button is released. + /** Removes a client from the list. - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseUp, mouseDrag, mouseDoubleClick, contains + This method will make sure that all callbacks to the client have completely + finished before the method returns. */ - virtual void mouseDown (const MouseEvent& e); + void removeTimeSliceClient (TimeSliceClient* const client); - /** Called when the mouse is moved while a button is held down. + /** Returns the number of registered clients. */ + int getNumClients() const throw(); - When a mouse button is pressed inside a component, that component - receives mouseDrag callbacks each time the mouse moves, even if the - mouse strays outside the component's bounds. + /** Returns one of the registered clients. */ + TimeSliceClient* getClient (const int index) const throw(); - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseUp, mouseMove, contains, setDragRepeatInterval - */ - virtual void mouseDrag (const MouseEvent& e); + /** @internal */ + void run(); - /** Called when a mouse button is released. + juce_UseDebuggingNewOperator - A mouseUp callback is sent to the component in which a button was pressed - even if the mouse is actually over a different component when the - button is released. +private: + CriticalSection callbackLock, listLock; + Array clients; + int index; + TimeSliceClient* clientBeingCalled; + bool clientsChanged; - The MouseEvent object passed in contains lots of methods for finding out - which buttons were down just before they were released. + TimeSliceThread (const TimeSliceThread&); + const TimeSliceThread& operator= (const TimeSliceThread&); +}; - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseDrag, mouseDoubleClick, contains - */ - virtual void mouseUp (const MouseEvent& e); +#endif // __JUCE_TIMESLICETHREAD_JUCEHEADER__ +/********* End of inlined file: juce_TimeSliceThread.h *********/ - /** Called when a mouse button has been double-clicked on a component. +#endif +#ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. +#endif - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @see mouseDown, mouseUp - */ - virtual void mouseDoubleClick (const MouseEvent& e); +#endif +/********* End of inlined file: juce_core_includes.h *********/ - /** Called when the mouse-wheel is moved. +// if you're compiling a command-line app, you might want to just include the core headers, +// so you can set this macro before including juce.h +#if ! JUCE_ONLY_BUILD_CORE_LIBRARY - This callback is sent to the component that the mouse is over when the - wheel is moved. +/********* Start of inlined file: juce_app_includes.h *********/ +#ifndef __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ +#define __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ - If not overridden, the component will forward this message to its parent, so - that parent components can collect mouse-wheel messages that happen to - child components which aren't interested in them. +#ifndef __JUCE_APPLICATION_JUCEHEADER__ - @param e details about the position and status of the mouse event, including - the source component in which it occurred - @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive - value means the wheel has been pushed to the right, negative means it - was pushed to the left - @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive - value means the wheel has been pushed upwards, negative means it - was pushed downwards - */ - virtual void mouseWheelMove (const MouseEvent& e, - float wheelIncrementX, - float wheelIncrementY); -}; +/********* Start of inlined file: juce_Application.h *********/ +#ifndef __JUCE_APPLICATION_JUCEHEADER__ +#define __JUCE_APPLICATION_JUCEHEADER__ -#endif // __JUCE_MOUSELISTENER_JUCEHEADER__ -/********* End of inlined file: juce_MouseListener.h *********/ +/********* Start of inlined file: juce_ApplicationCommandTarget.h *********/ +#ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ +#define __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ -/********* Start of inlined file: juce_ComponentListener.h *********/ -#ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__ -#define __JUCE_COMPONENTLISTENER_JUCEHEADER__ +/********* Start of inlined file: juce_Component.h *********/ +#ifndef __JUCE_COMPONENT_JUCEHEADER__ +#define __JUCE_COMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_MouseCursor.h *********/ +#ifndef __JUCE_MOUSECURSOR_JUCEHEADER__ +#define __JUCE_MOUSECURSOR_JUCEHEADER__ +class Image; +class RefCountedMouseCursor; +class ComponentPeer; class Component; /** - Gets informed about changes to a component's hierarchy or position. - - To monitor a component for changes, register a subclass of ComponentListener - with the component using Component::addComponentListener(). - - Be sure to deregister listeners before you delete them! + Represents a mouse cursor image. - @see Component::addComponentListener, Component::removeComponentListener + This object can either be used to represent one of the standard mouse + cursor shapes, or a custom one generated from an image. */ -class JUCE_API ComponentListener +class JUCE_API MouseCursor { public: - /** Destructor. */ - virtual ~ComponentListener() {} - /** Called when the component's position or size changes. + /** The set of available standard mouse cursors. */ + enum StandardCursorType + { + NoCursor = 0, /**< An invisible cursor. */ + NormalCursor, /**< The stardard arrow cursor. */ - @param component the component that was moved or resized - @param wasMoved true if the component's top-left corner has just moved - @param wasResized true if the component's width or height has just changed - @see Component::setBounds, Component::resized, Component::moved - */ - virtual void componentMovedOrResized (Component& component, - bool wasMoved, - bool wasResized); + WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */ + IBeamCursor, /**< A vertical I-beam for positioning within text. */ + CrosshairCursor, /**< A pair of crosshairs. */ + CopyingCursor, /**< The normal arrow cursor, but with a "+" on it to indicate + that you're dragging a copy of something. */ - /** Called when the component is brought to the top of the z-order. + PointingHandCursor, /**< A hand with a pointing finger, for clicking on web-links. */ + DraggingHandCursor, /**< An open flat hand for dragging heavy objects around. */ - @param component the component that was moved - @see Component::toFront, Component::broughtToFront + LeftRightResizeCursor, /**< An arrow pointing left and right. */ + UpDownResizeCursor, /**< an arrow pointing up and down. */ + UpDownLeftRightResizeCursor, /**< An arrow pointing up, down, left and right. */ + + TopEdgeResizeCursor, /**< A platform-specific cursor for resizing the top-edge of a window. */ + BottomEdgeResizeCursor, /**< A platform-specific cursor for resizing the bottom-edge of a window. */ + LeftEdgeResizeCursor, /**< A platform-specific cursor for resizing the left-edge of a window. */ + RightEdgeResizeCursor, /**< A platform-specific cursor for resizing the right-edge of a window. */ + TopLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the top-left-corner of a window. */ + TopRightCornerResizeCursor, /**< A platform-specific cursor for resizing the top-right-corner of a window. */ + BottomLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the bottom-left-corner of a window. */ + BottomRightCornerResizeCursor /**< A platform-specific cursor for resizing the bottom-right-corner of a window. */ + }; + + /** Creates the standard arrow cursor. */ + MouseCursor() throw(); + + /** Creates one of the standard mouse cursor */ + MouseCursor (const StandardCursorType type) throw(); + + /** Creates a custom cursor from an image. + + @param image the image to use for the cursor - if this is bigger than the + system can manage, it might get scaled down first, and might + also have to be turned to black-and-white if it can't do colour + cursors. + @param hotSpotX the x position of the cursor's hotspot within the image + @param hotSpotY the y position of the cursor's hotspot within the image */ - virtual void componentBroughtToFront (Component& component); + MouseCursor (Image& image, + const int hotSpotX, + const int hotSpotY) throw(); - /** Called when the component is made visible or invisible. + /** Creates a copy of another cursor object. */ + MouseCursor (const MouseCursor& other) throw(); - @param component the component that changed - @see Component::setVisible + /** Copies this cursor from another object. */ + const MouseCursor& operator= (const MouseCursor& other) throw(); + + /** Destructor. */ + ~MouseCursor() throw(); + + /** Checks whether two mouse cursors are the same. + + For custom cursors, two cursors created from the same image won't be + recognised as the same, only MouseCursor objects that have been + copied from the same object. */ - virtual void componentVisibilityChanged (Component& component); + bool operator== (const MouseCursor& other) const throw(); - /** Called when the component has children added or removed. + /** Checks whether two mouse cursors are the same. - @param component the component whose children were changed - @see Component::childrenChanged, Component::addChildComponent, - Component::removeChildComponent + For custom cursors, two cursors created from the same image won't be + recognised as the same, only MouseCursor objects that have been + copied from the same object. */ - virtual void componentChildrenChanged (Component& component); + bool operator!= (const MouseCursor& other) const throw(); - /** Called to indicate that the component's parents have changed. + /** Makes the system show its default 'busy' cursor. - When a component is added or removed from its parent, all of its children - will produce this notification (recursively - so all children of its - children will also be called as well). + This will turn the system cursor to an hourglass or spinning beachball + until the next time the mouse is moved, or hideWaitCursor() is called. - @param component the component that this listener is registered with - @see Component::parentHierarchyChanged + This is handy if the message loop is about to block for a couple of + seconds while busy and you want to give the user feedback about this. + + @see MessageManager::setTimeBeforeShowingWaitCursor */ - virtual void componentParentHierarchyChanged (Component& component); + static void showWaitCursor() throw(); - /** Called when the component's name is changed. + /** If showWaitCursor has been called, this will return the mouse to its + normal state. - @see Component::setName, Component::getName + This will look at what component is under the mouse, and update the + cursor to be the correct one for that component. + + @see showWaitCursor */ - virtual void componentNameChanged (Component& component); + static void hideWaitCursor() throw(); + + juce_UseDebuggingNewOperator + +private: + RefCountedMouseCursor* cursorHandle; + + friend class Component; + + void showInWindow (ComponentPeer* window) const throw(); + void showInAllWindows() const throw(); + + void* getHandle() const throw(); }; -#endif // __JUCE_COMPONENTLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_ComponentListener.h *********/ +#endif // __JUCE_MOUSECURSOR_JUCEHEADER__ +/********* End of inlined file: juce_MouseCursor.h *********/ -/********* Start of inlined file: juce_KeyListener.h *********/ -#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ -#define __JUCE_KEYLISTENER_JUCEHEADER__ +/********* Start of inlined file: juce_MouseListener.h *********/ +#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__ +#define __JUCE_MOUSELISTENER_JUCEHEADER__ -/********* Start of inlined file: juce_KeyPress.h *********/ -#ifndef __JUCE_KEYPRESS_JUCEHEADER__ -#define __JUCE_KEYPRESS_JUCEHEADER__ +/********* Start of inlined file: juce_MouseEvent.h *********/ +#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__ +#define __JUCE_MOUSEEVENT_JUCEHEADER__ + +class Component; + +/********* Start of inlined file: juce_ModifierKeys.h *********/ +#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ +#define __JUCE_MODIFIERKEYS_JUCEHEADER__ /** - Represents a key press, including any modifier keys that are needed. + Represents the state of the mouse buttons and modifier keys. - E.g. a KeyPress might represent CTRL+C, SHIFT+ALT+H, Spacebar, Escape, etc. + This is used both by mouse events and by KeyPress objects to describe + the state of keys such as shift, control, alt, etc. - @see Component, KeyListener, Button::addShortcut, KeyPressMappingManager + @see KeyPress, MouseEvent::mods */ -class JUCE_API KeyPress +class JUCE_API ModifierKeys { public: - /** Creates an (invalid) KeyPress. + /** Creates a ModifierKeys object from a raw set of flags. - @see isValid + @param flags to represent the keys that are down + @see shiftModifier, ctrlModifier, altModifier, leftButtonModifier, + rightButtonModifier, commandModifier, popupMenuClickModifier */ - KeyPress() throw(); + ModifierKeys (const int flags = 0) throw(); - /** Creates a KeyPress for a key and some modifiers. + /** Creates a copy of another object. */ + ModifierKeys (const ModifierKeys& other) throw(); - e.g. - CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier) - SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier) + /** Copies this object from another one. */ + const ModifierKeys& operator= (const ModifierKeys& other) throw(); - @param keyCode a code that represents the key - this value must be - one of special constants listed in this class, or an - 8-bit character code such as a letter (case is ignored), - digit or a simple key like "," or ".". Note that this - isn't the same as the textCharacter parameter, so for example - a keyCode of 'a' and a shift-key modifier should have a - textCharacter value of 'A'. - @param modifiers the modifiers to associate with the keystroke - @param textCharacter the character that would be printed if someone typed - this keypress into a text editor. This value may be - null if the keypress is a non-printing character - @see getKeyCode, isKeyCode, getModifiers - */ - KeyPress (const int keyCode, - const ModifierKeys& modifiers, - const juce_wchar textCharacter) throw(); + /** Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux). - /** Creates a keypress with a keyCode but no modifiers or text character. + This is a platform-agnostic way of checking for the operating system's + preferred command-key modifier - so on the Mac it tests for the Apple key, on + Windows/Linux, it's actually checking for the CTRL key. */ - KeyPress (const int keyCode) throw(); - - /** Creates a copy of another KeyPress. */ - KeyPress (const KeyPress& other) throw(); - - /** Copies this KeyPress from another one. */ - const KeyPress& operator= (const KeyPress& other) throw(); - - /** Compares two KeyPress objects. */ - bool operator== (const KeyPress& other) const throw(); + inline bool isCommandDown() const throw() { return (flags & commandModifier) != 0; } - /** Compares two KeyPress objects. */ - bool operator!= (const KeyPress& other) const throw(); + /** Checks whether the user is trying to launch a pop-up menu. - /** Returns true if this is a valid KeyPress. + This checks for platform-specific modifiers that might indicate that the user + is following the operating system's normal method of showing a pop-up menu. - A null keypress can be created by the default constructor, in case it's - needed. + So on Windows/Linux, this method is really testing for a right-click. + On the Mac, it tests for either the CTRL key being down, or a right-click. */ - bool isValid() const throw() { return keyCode != 0; } + inline bool isPopupMenu() const throw() { return (flags & popupMenuClickModifier) != 0; } - /** Returns the key code itself. + /** Checks whether the flag is set for the left mouse-button. */ + inline bool isLeftButtonDown() const throw() { return (flags & leftButtonModifier) != 0; } - This will either be one of the special constants defined in this class, - or an 8-bit character code. + /** Checks whether the flag is set for the right mouse-button. + + Note that for detecting popup-menu clicks, you should be using isPopupMenu() instead, as + this is platform-independent (and makes your code more explanatory too). */ - int getKeyCode() const throw() { return keyCode; } + inline bool isRightButtonDown() const throw() { return (flags & rightButtonModifier) != 0; } - /** Returns the key modifiers. + inline bool isMiddleButtonDown() const throw() { return (flags & middleButtonModifier) != 0; } - @see ModifierKeys - */ - const ModifierKeys getModifiers() const throw() { return mods; } + /** Tests for any of the mouse-button flags. */ + inline bool isAnyMouseButtonDown() const throw() { return (flags & allMouseButtonModifiers) != 0; } - /** Returns the character that is associated with this keypress. + /** Tests for any of the modifier key flags. */ + inline bool isAnyModifierKeyDown() const throw() { return (flags & (shiftModifier | ctrlModifier | altModifier | commandModifier)) != 0; } - This is the character that you'd expect to see printed if you press this - keypress in a text editor or similar component. - */ - juce_wchar getTextCharacter() const throw() { return textCharacter; } + /** Checks whether the shift key's flag is set. */ + inline bool isShiftDown() const throw() { return (flags & shiftModifier) != 0; } - /** Checks whether the KeyPress's key is the same as the one provided, without checking - the modifiers. + /** Checks whether the CTRL key's flag is set. - The values for key codes can either be one of the special constants defined in - this class, or an 8-bit character code. + Remember that it's better to use the platform-agnostic routines to test for command-key and + popup-menu modifiers. - @see getKeyCode + @see isCommandDown, isPopupMenu */ - bool isKeyCode (const int keyCodeToCompare) const throw() { return keyCode == keyCodeToCompare; } + inline bool isCtrlDown() const throw() { return (flags & ctrlModifier) != 0; } - /** Converts a textual key description to a KeyPress. + /** Checks whether the shift key's flag is set. */ + inline bool isAltDown() const throw() { return (flags & altModifier) != 0; } - This attempts to decode a textual version of a keypress, e.g. "CTRL + C" or "SPACE". + /** Flags that represent the different keys. */ + enum Flags + { + /** Shift key flag. */ + shiftModifier = 1, - This isn't designed to cope with any kind of input, but should be given the - strings that are created by the getTextDescription() method. + /** CTRL key flag. */ + ctrlModifier = 2, - If the string can't be parsed, the object returned will be invalid. + /** ALT key flag. */ + altModifier = 4, - @see getTextDescription - */ - static const KeyPress createFromDescription (const String& textVersion) throw(); + /** Left mouse button flag. */ + leftButtonModifier = 16, - /** Creates a textual description of the key combination. + /** Right mouse button flag. */ + rightButtonModifier = 32, - e.g. "CTRL + C" or "DELETE". + /** Middle mouse button flag. */ + middleButtonModifier = 64, - To store a keypress in a file, use this method, along with createFromDescription() - to retrieve it later. - */ - const String getTextDescription() const throw(); +#if JUCE_MAC + /** Command key flag - on windows this is the same as the CTRL key flag. */ + commandModifier = 8, - /** Checks whether the user is currently holding down the keys that make up this - KeyPress. + /** Popup menu flag - on windows this is the same as rightButtonModifier, on the + Mac it's the same as (rightButtonModifier | ctrlModifier). */ + popupMenuClickModifier = rightButtonModifier | ctrlModifier, +#else + /** Command key flag - on windows this is the same as the CTRL key flag. */ + commandModifier = ctrlModifier, - Note that this will return false if any extra modifier keys are - down - e.g. if the keypress is CTRL+X and the user is actually holding CTRL+ALT+x - then it will be false. - */ - bool isCurrentlyDown() const throw(); + /** Popup menu flag - on windows this is the same as rightButtonModifier, on the + Mac it's the same as (rightButtonModifier | ctrlModifier). */ + popupMenuClickModifier = rightButtonModifier, +#endif - /** Checks whether a particular key is held down, irrespective of modifiers. + /** Represents a combination of all the shift, alt, ctrl and command key modifiers. */ + allKeyboardModifiers = shiftModifier | ctrlModifier | altModifier | commandModifier, - The values for key codes can either be one of the special constants defined in - this class, or an 8-bit character code. - */ - static bool isKeyCurrentlyDown (int keyCode) throw(); + /** Represents a combination of all the mouse buttons at once. */ + allMouseButtonModifiers = leftButtonModifier | rightButtonModifier | middleButtonModifier, + }; - // Key codes - // - // Note that the actual values of these are platform-specific and may change - // without warning, so don't store them anywhere as constants. For persisting/retrieving - // KeyPress objects, use getTextDescription() and createFromDescription() instead. - // + /** Returns the raw flags for direct testing. */ + inline int getRawFlags() const throw() { return flags; } - static const int spaceKey; /**< key-code for the space bar */ - static const int escapeKey; /**< key-code for the escape key */ - static const int returnKey; /**< key-code for the return key*/ - static const int tabKey; /**< key-code for the tab key*/ + /** Tests a combination of flags and returns true if any of them are set. */ + inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } - static const int deleteKey; /**< key-code for the delete key (not backspace) */ - static const int backspaceKey; /**< key-code for the backspace key */ - static const int insertKey; /**< key-code for the insert key */ + /** Creates a ModifierKeys object to represent the last-known state of the + keyboard and mouse buttons. - static const int upKey; /**< key-code for the cursor-up key */ - static const int downKey; /**< key-code for the cursor-down key */ - static const int leftKey; /**< key-code for the cursor-left key */ - static const int rightKey; /**< key-code for the cursor-right key */ - static const int pageUpKey; /**< key-code for the page-up key */ - static const int pageDownKey; /**< key-code for the page-down key */ - static const int homeKey; /**< key-code for the home key */ - static const int endKey; /**< key-code for the end key */ + @see getCurrentModifiersRealtime + */ + static const ModifierKeys getCurrentModifiers() throw(); - static const int F1Key; /**< key-code for the F1 key */ - static const int F2Key; /**< key-code for the F2 key */ - static const int F3Key; /**< key-code for the F3 key */ - static const int F4Key; /**< key-code for the F4 key */ - static const int F5Key; /**< key-code for the F5 key */ - static const int F6Key; /**< key-code for the F6 key */ - static const int F7Key; /**< key-code for the F7 key */ - static const int F8Key; /**< key-code for the F8 key */ - static const int F9Key; /**< key-code for the F9 key */ - static const int F10Key; /**< key-code for the F10 key */ - static const int F11Key; /**< key-code for the F11 key */ - static const int F12Key; /**< key-code for the F12 key */ - static const int F13Key; /**< key-code for the F13 key */ - static const int F14Key; /**< key-code for the F14 key */ - static const int F15Key; /**< key-code for the F15 key */ - static const int F16Key; /**< key-code for the F16 key */ + /** Creates a ModifierKeys object to represent the current state of the + keyboard and mouse buttons. - static const int numberPad0; /**< key-code for the 0 on the numeric keypad. */ - static const int numberPad1; /**< key-code for the 1 on the numeric keypad. */ - static const int numberPad2; /**< key-code for the 2 on the numeric keypad. */ - static const int numberPad3; /**< key-code for the 3 on the numeric keypad. */ - static const int numberPad4; /**< key-code for the 4 on the numeric keypad. */ - static const int numberPad5; /**< key-code for the 5 on the numeric keypad. */ - static const int numberPad6; /**< key-code for the 6 on the numeric keypad. */ - static const int numberPad7; /**< key-code for the 7 on the numeric keypad. */ - static const int numberPad8; /**< key-code for the 8 on the numeric keypad. */ - static const int numberPad9; /**< key-code for the 9 on the numeric keypad. */ + This isn't often needed and isn't recommended, but will actively check all the + mouse and key states rather than just returning their last-known state like + getCurrentModifiers() does. - static const int numberPadAdd; /**< key-code for the add sign on the numeric keypad. */ - static const int numberPadSubtract; /**< key-code for the subtract sign on the numeric keypad. */ - static const int numberPadMultiply; /**< key-code for the multiply sign on the numeric keypad. */ - static const int numberPadDivide; /**< key-code for the divide sign on the numeric keypad. */ - static const int numberPadSeparator; /**< key-code for the comma on the numeric keypad. */ - static const int numberPadDecimalPoint; /**< key-code for the decimal point sign on the numeric keypad. */ - static const int numberPadEquals; /**< key-code for the equals key on the numeric keypad. */ - static const int numberPadDelete; /**< key-code for the delete key on the numeric keypad. */ + This is only needed in special circumstances for up-to-date modifier information + at times when the app's event loop isn't running normally. + */ + static const ModifierKeys getCurrentModifiersRealtime() throw(); - static const int playKey; /**< key-code for a multimedia 'play' key, (not all keyboards will have one) */ - static const int stopKey; /**< key-code for a multimedia 'stop' key, (not all keyboards will have one) */ - static const int fastForwardKey; /**< key-code for a multimedia 'fast-forward' key, (not all keyboards will have one) */ - static const int rewindKey; /**< key-code for a multimedia 'rewind' key, (not all keyboards will have one) */ +private: - juce_UseDebuggingNewOperator + int flags; -private: + static int currentModifierFlags; - int keyCode; - ModifierKeys mods; - juce_wchar textCharacter; + friend class ComponentPeer; + static void updateCurrentModifiers() throw(); }; -#endif // __JUCE_KEYPRESS_JUCEHEADER__ -/********* End of inlined file: juce_KeyPress.h *********/ - -class Component; +#endif // __JUCE_MODIFIERKEYS_JUCEHEADER__ +/********* End of inlined file: juce_ModifierKeys.h *********/ /** - Receives callbacks when keys are pressed. - - You can add a key listener to a component to be informed when that component - gets key events. See the Component::addListener method for more details. + Contains position and status information about a mouse event. - @see KeyPress, Component::addKeyListener, KeyPressMappingManager + @see MouseListener, Component::mouseMove, Component::mouseEnter, Component::mouseExit, + Component::mouseDown, Component::mouseUp, Component::mouseDrag */ -class JUCE_API KeyListener +class JUCE_API MouseEvent { public: - /** Destructor. */ - virtual ~KeyListener() {} - /** Called to indicate that a key has been pressed. + /** Creates a MouseEvent. - If your implementation returns true, then the key event is considered to have - been consumed, and will not be passed on to any other components. If it returns - false, then the key will be passed to other components that might want to use it. + Normally an application will never need to use this. - @param key the keystroke, including modifier keys - @param originatingComponent the component that received the key event - @see keyStateChanged, Component::keyPressed + @param x the x position of the mouse, relative to the component that is passed-in + @param y the y position of the mouse, relative to the component that is passed-in + @param modifiers the key modifiers at the time of the event + @param originator the component that the mouse event applies to + @param eventTime the time the event happened + @param mouseDownX the x position of the corresponding mouse-down event (relative to the component that is passed-in). + If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be + the same as the current mouse-x position. + @param mouseDownY the y position of the corresponding mouse-down event (relative to the component that is passed-in) + If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be + the same as the current mouse-y position. + @param mouseDownTime the time at which the corresponding mouse-down event happened + If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be + the same as the current mouse-event time. + @param numberOfClicks how many clicks, e.g. a double-click event will be 2, a triple-click will be 3, etc + @param mouseWasDragged whether the mouse has been dragged significantly since the previous mouse-down */ - virtual bool keyPressed (const KeyPress& key, - Component* originatingComponent) = 0; - - /** Called when any key is pressed or released. + MouseEvent (const int x, const int y, + const ModifierKeys& modifiers, + Component* const originator, + const Time& eventTime, + const int mouseDownX, + const int mouseDownY, + const Time& mouseDownTime, + const int numberOfClicks, + const bool mouseWasDragged) throw(); - When this is called, classes that might be interested in - the state of one or more keys can use KeyPress::isKeyCurrentlyDown() to - check whether their key has changed. + /** Destructor. */ + ~MouseEvent() throw(); - If your implementation returns true, then the key event is considered to have - been consumed, and will not be passed on to any other components. If it returns - false, then the key will be passed to other components that might want to use it. + /** The x-position of the mouse when the event occurred. - @param originatingComponent the component that received the key event - @param isKeyDown true if a key is being pressed, false if one is being released - @see KeyPress, Component::keyStateChanged + This value is relative to the top-left of the component to which the + event applies (as indicated by the MouseEvent::eventComponent field). */ - virtual bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); -}; - -#endif // __JUCE_KEYLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_KeyListener.h *********/ + int x; -/********* Start of inlined file: juce_KeyboardFocusTraverser.h *********/ -#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ -#define __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ + /** The y-position of the mouse when the event occurred. -class Component; + This value is relative to the top-left of the component to which the + event applies (as indicated by the MouseEvent::eventComponent field). + */ + int y; -/** - Controls the order in which focus moves between components. + /** The key modifiers associated with the event. - The default algorithm used by this class to work out the order of traversal - is as follows: - - if two components both have an explicit focus order specified, then the - one with the lowest number comes first (see the Component::setExplicitFocusOrder() - method). - - any component with an explicit focus order greater than 0 comes before ones - that don't have an order specified. - - any unspecified components are traversed in a left-to-right, then top-to-bottom - order. + This will let you find out which mouse buttons were down, as well as which + modifier keys were held down. - If you need traversal in a more customised way, you can create a subclass - of KeyboardFocusTraverser that uses your own algorithm, and use - Component::createFocusTraverser() to create it. + When used for mouse-up events, this will indicate the state of the mouse buttons + just before they were released, so that you can tell which button they let go of. + */ + ModifierKeys mods; - @see Component::setExplicitFocusOrder, Component::createFocusTraverser -*/ -class JUCE_API KeyboardFocusTraverser -{ -public: - KeyboardFocusTraverser(); + /** The component that this event applies to. - /** Destructor. */ - virtual ~KeyboardFocusTraverser(); + This is usually the component that the mouse was over at the time, but for mouse-drag + events the mouse could actually be over a different component and the events are + still sent to the component that the button was originally pressed on. - /** Returns the component that should be given focus after the specified one - when moving "forwards". + The x and y member variables are relative to this component's position. - The default implementation will return the next component which is to the - right of or below this one. + If you use getEventRelativeTo() to retarget this object to be relative to a different + component, this pointer will be updated, but originalComponent remains unchanged. - This may return 0 if there's no suitable candidate. + @see originalComponent */ - virtual Component* getNextComponent (Component* current); + Component* eventComponent; - /** Returns the component that should be given focus after the specified one - when moving "backwards". + /** The component that the event first occurred on. - The default implementation will return the next component which is to the - left of or above this one. + If you use getEventRelativeTo() to retarget this object to be relative to a different + component, this value remains unchanged to indicate the first component that received it. - This may return 0 if there's no suitable candidate. + @see eventComponent */ - virtual Component* getPreviousComponent (Component* current); - - /** Returns the component that should receive focus be default within the given - parent component. - - The default implementation will just return the foremost child component that - wants focus. + Component* originalComponent; - This may return 0 if there's no suitable candidate. + /** The time that this mouse-event occurred. */ - virtual Component* getDefaultComponent (Component* parentComponent); -}; - -#endif // __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ -/********* End of inlined file: juce_KeyboardFocusTraverser.h *********/ - -/********* Start of inlined file: juce_ImageEffectFilter.h *********/ -#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ -#define __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ - -/********* Start of inlined file: juce_Graphics.h *********/ -#ifndef __JUCE_GRAPHICS_JUCEHEADER__ -#define __JUCE_GRAPHICS_JUCEHEADER__ + Time eventTime; -/********* Start of inlined file: juce_Font.h *********/ -#ifndef __JUCE_FONT_JUCEHEADER__ -#define __JUCE_FONT_JUCEHEADER__ + /** Returns the x co-ordinate of the last place that a mouse was pressed. -/********* Start of inlined file: juce_Typeface.h *********/ -#ifndef __JUCE_TYPEFACE_JUCEHEADER__ -#define __JUCE_TYPEFACE_JUCEHEADER__ + The co-ordinate is relative to the component specified in MouseEvent::component. -/********* Start of inlined file: juce_Path.h *********/ -#ifndef __JUCE_PATH_JUCEHEADER__ -#define __JUCE_PATH_JUCEHEADER__ + @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked + */ + int getMouseDownX() const throw(); -/********* Start of inlined file: juce_AffineTransform.h *********/ -#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ -#define __JUCE_AFFINETRANSFORM_JUCEHEADER__ + /** Returns the y co-ordinate of the last place that a mouse was pressed. -/** - Represents a 2D affine-transformation matrix. + The co-ordinate is relative to the component specified in MouseEvent::component. - An affine transformation is a transformation such as a rotation, scale, shear, - resize or translation. + @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked + */ + int getMouseDownY() const throw(); - These are used for various 2D transformation tasks, e.g. with Path objects. + /** Returns the straight-line distance between where the mouse is now and where it + was the last time the button was pressed. - @see Path, Point, Line -*/ -class JUCE_API AffineTransform -{ -public: + This is quite handy for things like deciding whether the user has moved far enough + for it to be considered a drag operation. - /** Creates an identity transform. */ - AffineTransform() throw(); + @see getDistanceFromDragStartX + */ + int getDistanceFromDragStart() const throw(); - /** Creates a copy of another transform. */ - AffineTransform (const AffineTransform& other) throw(); + /** Returns the difference between the mouse's current x postion and where it was + when the button was last pressed. - /** Creates a transform from a set of raw matrix values. + @see getDistanceFromDragStart + */ + int getDistanceFromDragStartX() const throw(); - The resulting matrix is: + /** Returns the difference between the mouse's current y postion and where it was + when the button was last pressed. - (mat00 mat01 mat02) - (mat10 mat11 mat12) - ( 0 0 1 ) + @see getDistanceFromDragStart */ - AffineTransform (const float mat00, const float mat01, const float mat02, - const float mat10, const float mat11, const float mat12) throw(); + int getDistanceFromDragStartY() const throw(); - /** Copies from another AffineTransform object */ - const AffineTransform& operator= (const AffineTransform& other) throw(); + /** Returns true if the mouse has just been clicked. - /** Compares two transforms. */ - bool operator== (const AffineTransform& other) const throw(); + Used in either your mouseUp() or mouseDrag() methods, this will tell you whether + the user has dragged the mouse more than a few pixels from the place where the + mouse-down occurred. - /** Compares two transforms. */ - bool operator!= (const AffineTransform& other) const throw(); + Once they have dragged it far enough for this method to return false, it will continue + to return false until the mouse-up, even if they move the mouse back to the same + position where they originally pressed it. This means that it's very handy for + objects that can either be clicked on or dragged, as you can use it in the mouseDrag() + callback to ignore any small movements they might make while clicking. - /** A ready-to-use identity transform, which you can use to append other - transformations to. + @returns true if the mouse wasn't dragged by more than a few pixels between + the last time the button was pressed and released. + */ + bool mouseWasClicked() const throw(); - e.g. @code - AffineTransform myTransform = AffineTransform::identity.rotated (.5f) - .scaled (2.0f); + /** For a click event, the number of times the mouse was clicked in succession. - @endcode + So for example a double-click event will return 2, a triple-click 3, etc. */ - static const AffineTransform identity; - - /** Transforms a 2D co-ordinate using this matrix. */ - void transformPoint (float& x, - float& y) const throw(); + int getNumberOfClicks() const throw() { return numberOfClicks; } - /** Transforms a 2D co-ordinate using this matrix. */ - void transformPoint (double& x, - double& y) const throw(); + /** Returns the time that the mouse button has been held down for. - /** Returns a new transform which is the same as this one followed by a translation. */ - const AffineTransform translated (const float deltaX, - const float deltaY) const throw(); + If called from a mouseDrag or mouseUp callback, this will return the + number of milliseconds since the corresponding mouseDown event occurred. + If called in other contexts, e.g. a mouseMove, then the returned value + may be 0 or an undefined value. + */ + int getLengthOfMousePress() const throw(); - /** Returns a new transform which is a translation. */ - static const AffineTransform translation (const float deltaX, - const float deltaY) throw(); + /** Returns the mouse x position of this event, in global screen co-ordinates. - /** Returns a transform which is the same as this one followed by a rotation. + The co-ordinates are relative to the top-left of the main monitor. - The rotation is specified by a number of radians to rotate clockwise, centred around - the origin (0, 0). + @see getMouseDownScreenX, Desktop::getMousePosition */ - const AffineTransform rotated (const float angleInRadians) const throw(); + int getScreenX() const throw(); - /** Returns a transform which is the same as this one followed by a rotation about a given point. + /** Returns the mouse y position of this event, in global screen co-ordinates. - The rotation is specified by a number of radians to rotate clockwise, centred around - the co-ordinates passed in. - */ - const AffineTransform rotated (const float angleInRadians, - const float pivotX, - const float pivotY) const throw(); + The co-ordinates are relative to the top-left of the main monitor. - /** Returns a new transform which is a rotation about (0, 0). */ - static const AffineTransform rotation (const float angleInRadians) throw(); + @see getMouseDownScreenY, Desktop::getMousePosition + */ + int getScreenY() const throw(); - /** Returns a new transform which is a rotation about a given point. */ - static const AffineTransform rotation (const float angleInRadians, - const float pivotX, - const float pivotY) throw(); + /** Returns the x co-ordinate at which the mouse button was last pressed. - /** Returns a transform which is the same as this one followed by a re-scaling. + The co-ordinates are relative to the top-left of the main monitor. - The scaling is centred around the origin (0, 0). + @see getScreenX, Desktop::getMousePosition */ - const AffineTransform scaled (const float factorX, - const float factorY) const throw(); + int getMouseDownScreenX() const throw(); - /** Returns a new transform which is a re-scale about the origin. */ - static const AffineTransform scale (const float factorX, - const float factorY) throw(); + /** Returns the y co-ordinate at which the mouse button was last pressed. - /** Returns a transform which is the same as this one followed by a shear. + The co-ordinates are relative to the top-left of the main monitor. - The shear is centred around the origin (0, 0). + @see getScreenY, Desktop::getMousePosition */ - const AffineTransform sheared (const float shearX, - const float shearY) const throw(); + int getMouseDownScreenY() const throw(); - /** Returns a matrix which is the inverse operation of this one. + /** Creates a version of this event that is relative to a different component. - Some matrices don't have an inverse - in this case, the method will just return - an identity transform. + The x and y positions of the event that is returned will have been + adjusted to be relative to the new component. */ - const AffineTransform inverted() const throw(); + const MouseEvent getEventRelativeTo (Component* const otherComponent) const throw(); - /** Returns the result of concatenating another transformation after this one. */ - const AffineTransform followedBy (const AffineTransform& other) const throw(); + /** Changes the application-wide setting for the double-click time limit. - /** Returns true if this transform has no effect on points. */ - bool isIdentity() const throw(); + This is the maximum length of time between mouse-clicks for it to be + considered a double-click. It's used by the Component class. - /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */ - bool isSingularity() const throw(); + @see getDoubleClickTimeout, MouseListener::mouseDoubleClick + */ + static void setDoubleClickTimeout (const int timeOutMilliseconds) throw(); - /** Returns true if the transform only translates, and doesn't scale or rotate the - points. */ - bool isOnlyTranslation() const throw(); + /** Returns the application-wide setting for the double-click time limit. - /** If this transform is only a translation, this returns the X offset. - @see isOnlyTranslation - */ - float getTranslationX() const throw() { return mat02; } + This is the maximum length of time between mouse-clicks for it to be + considered a double-click. It's used by the Component class. - /** If this transform is only a translation, this returns the X offset. - @see isOnlyTranslation + @see setDoubleClickTimeout, MouseListener::mouseDoubleClick */ - float getTranslationY() const throw() { return mat12; } + static int getDoubleClickTimeout() throw(); juce_UseDebuggingNewOperator - /* The transform matrix is: - - (mat00 mat01 mat02) - (mat10 mat11 mat12) - ( 0 0 1 ) - */ - float mat00, mat01, mat02; - float mat10, mat11, mat12; - private: - - const AffineTransform followedBy (const float mat00, const float mat01, const float mat02, - const float mat10, const float mat11, const float mat12) const throw(); + int mouseDownX, mouseDownY; + Time mouseDownTime; + int numberOfClicks; + bool wasMovedSinceMouseDown; }; -#endif // __JUCE_AFFINETRANSFORM_JUCEHEADER__ -/********* End of inlined file: juce_AffineTransform.h *********/ - -/********* Start of inlined file: juce_Point.h *********/ -#ifndef __JUCE_POINT_JUCEHEADER__ -#define __JUCE_POINT_JUCEHEADER__ +#endif // __JUCE_MOUSEEVENT_JUCEHEADER__ +/********* End of inlined file: juce_MouseEvent.h *********/ /** - A pair of (x, y) co-ordinates. - - Uses 32-bit floating point accuracy. + A MouseListener can be registered with a component to receive callbacks + about mouse events that happen to that component. - @see Line, Path, AffineTransform + @see Component::addMouseListener, Component::removeMouseListener */ -class JUCE_API Point +class JUCE_API MouseListener { public: + /** Destructor. */ + virtual ~MouseListener() {} - /** Creates a point with co-ordinates (0, 0). */ - Point() throw(); + /** Called when the mouse moves inside a component. - /** Creates a copy of another point. */ - Point (const Point& other) throw(); + If the mouse button isn't pressed and the mouse moves over a component, + this will be called to let the component react to this. - /** Creates a point from an (x, y) position. */ - Point (const float x, const float y) throw(); + A component will always get a mouseEnter callback before a mouseMove. - /** Copies this point from another one. - @see setXY + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseEnter, mouseExit, mouseDrag, contains */ - const Point& operator= (const Point& other) throw(); + virtual void mouseMove (const MouseEvent& e); - /** Destructor. */ - ~Point() throw(); + /** Called when the mouse first enters a component. - /** Returns the point's x co-ordinate. */ - inline float getX() const throw() { return x; } + If the mouse button isn't pressed and the mouse moves into a component, + this will be called to let the component react to this. - /** Returns the point's y co-ordinate. */ - inline float getY() const throw() { return y; } + When the mouse button is pressed and held down while being moved in + or out of a component, no mouseEnter or mouseExit callbacks are made - only + mouseDrag messages are sent to the component that the mouse was originally + clicked on, until the button is released. - /** Changes the point's x and y co-ordinates. */ - void setXY (const float x, - const float y) throw(); + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseExit, mouseDrag, mouseMove, contains + */ + virtual void mouseEnter (const MouseEvent& e); - /** Uses a transform to change the point's co-ordinates. + /** Called when the mouse moves out of a component. - @see AffineTransform::transformPoint + This will be called when the mouse moves off the edge of this + component. + + If the mouse button was pressed, and it was then dragged off the + edge of the component and released, then this callback will happen + when the button is released, after the mouseUp callback. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseEnter, mouseDrag, mouseMove, contains */ - void applyTransform (const AffineTransform& transform) throw(); + virtual void mouseExit (const MouseEvent& e); - juce_UseDebuggingNewOperator + /** Called when a mouse button is pressed. -private: - float x, y; + The MouseEvent object passed in contains lots of methods for finding out + which button was pressed, as well as which modifier keys (e.g. shift, ctrl) + were held down at the time. + + Once a button is held down, the mouseDrag method will be called when the + mouse moves, until the button is released. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseUp, mouseDrag, mouseDoubleClick, contains + */ + virtual void mouseDown (const MouseEvent& e); + + /** Called when the mouse is moved while a button is held down. + + When a mouse button is pressed inside a component, that component + receives mouseDrag callbacks each time the mouse moves, even if the + mouse strays outside the component's bounds. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseDown, mouseUp, mouseMove, contains, setDragRepeatInterval + */ + virtual void mouseDrag (const MouseEvent& e); + + /** Called when a mouse button is released. + + A mouseUp callback is sent to the component in which a button was pressed + even if the mouse is actually over a different component when the + button is released. + + The MouseEvent object passed in contains lots of methods for finding out + which buttons were down just before they were released. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseDown, mouseDrag, mouseDoubleClick, contains + */ + virtual void mouseUp (const MouseEvent& e); + + /** Called when a mouse button has been double-clicked on a component. + + The MouseEvent object passed in contains lots of methods for finding out + which button was pressed, as well as which modifier keys (e.g. shift, ctrl) + were held down at the time. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @see mouseDown, mouseUp + */ + virtual void mouseDoubleClick (const MouseEvent& e); + + /** Called when the mouse-wheel is moved. + + This callback is sent to the component that the mouse is over when the + wheel is moved. + + If not overridden, the component will forward this message to its parent, so + that parent components can collect mouse-wheel messages that happen to + child components which aren't interested in them. + + @param e details about the position and status of the mouse event, including + the source component in which it occurred + @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive + value means the wheel has been pushed to the right, negative means it + was pushed to the left + @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive + value means the wheel has been pushed upwards, negative means it + was pushed downwards + */ + virtual void mouseWheelMove (const MouseEvent& e, + float wheelIncrementX, + float wheelIncrementY); }; -#endif // __JUCE_POINT_JUCEHEADER__ -/********* End of inlined file: juce_Point.h *********/ +#endif // __JUCE_MOUSELISTENER_JUCEHEADER__ +/********* End of inlined file: juce_MouseListener.h *********/ -/********* Start of inlined file: juce_Rectangle.h *********/ -#ifndef __JUCE_RECTANGLE_JUCEHEADER__ -#define __JUCE_RECTANGLE_JUCEHEADER__ +/********* Start of inlined file: juce_ComponentListener.h *********/ +#ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__ +#define __JUCE_COMPONENTLISTENER_JUCEHEADER__ + +class Component; /** - A rectangle, specified using integer co-ordinates. + Gets informed about changes to a component's hierarchy or position. - @see RectangleList, Path, Line, Point + To monitor a component for changes, register a subclass of ComponentListener + with the component using Component::addComponentListener(). + + Be sure to deregister listeners before you delete them! + + @see Component::addComponentListener, Component::removeComponentListener */ -class JUCE_API Rectangle +class JUCE_API ComponentListener { public: + /** Destructor. */ + virtual ~ComponentListener() {} - /** Creates a rectangle of zero size. + /** Called when the component's position or size changes. - The default co-ordinates will be (0, 0, 0, 0). + @param component the component that was moved or resized + @param wasMoved true if the component's top-left corner has just moved + @param wasResized true if the component's width or height has just changed + @see Component::setBounds, Component::resized, Component::moved */ - Rectangle() throw(); + virtual void componentMovedOrResized (Component& component, + bool wasMoved, + bool wasResized); - /** Creates a copy of another rectangle. */ - Rectangle (const Rectangle& other) throw(); + /** Called when the component is brought to the top of the z-order. - /** Creates a rectangle with a given position and size. */ - Rectangle (const int x, const int y, - const int width, const int height) throw(); + @param component the component that was moved + @see Component::toFront, Component::broughtToFront + */ + virtual void componentBroughtToFront (Component& component); - /** Creates a rectangle with a given size, and a position of (0, 0). */ - Rectangle (const int width, const int height) throw(); + /** Called when the component is made visible or invisible. - /** Destructor. */ - ~Rectangle() throw(); + @param component the component that changed + @see Component::setVisible + */ + virtual void componentVisibilityChanged (Component& component); - /** Returns the x co-ordinate of the rectangle's left-hand-side. */ - inline int getX() const throw() { return x; } + /** Called when the component has children added or removed. - /** Returns the y co-ordinate of the rectangle's top edge. */ - inline int getY() const throw() { return y; } + @param component the component whose children were changed + @see Component::childrenChanged, Component::addChildComponent, + Component::removeChildComponent + */ + virtual void componentChildrenChanged (Component& component); - /** Returns the width of the rectangle. */ - inline int getWidth() const throw() { return w; } + /** Called to indicate that the component's parents have changed. - /** Returns the height of the rectangle. */ - inline int getHeight() const throw() { return h; } + When a component is added or removed from its parent, all of its children + will produce this notification (recursively - so all children of its + children will also be called as well). - /** Returns the x co-ordinate of the rectangle's right-hand-side. */ - inline int getRight() const throw() { return x + w; } + @param component the component that this listener is registered with + @see Component::parentHierarchyChanged + */ + virtual void componentParentHierarchyChanged (Component& component); - /** Returns the y co-ordinate of the rectangle's bottom edge. */ - inline int getBottom() const throw() { return y + h; } + /** Called when the component's name is changed. - /** Returns the x co-ordinate of the rectangle's centre. */ - inline int getCentreX() const throw() { return x + (w >> 1); } + @see Component::setName, Component::getName + */ + virtual void componentNameChanged (Component& component); +}; - /** Returns the y co-ordinate of the rectangle's centre. */ - inline int getCentreY() const throw() { return y + (h >> 1); } +#endif // __JUCE_COMPONENTLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_ComponentListener.h *********/ - /** Returns true if the rectangle's width and height are both zero or less */ - bool isEmpty() const throw(); +/********* Start of inlined file: juce_KeyListener.h *********/ +#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ +#define __JUCE_KEYLISTENER_JUCEHEADER__ - /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ - void setPosition (const int x, const int y) throw(); +/********* Start of inlined file: juce_KeyPress.h *********/ +#ifndef __JUCE_KEYPRESS_JUCEHEADER__ +#define __JUCE_KEYPRESS_JUCEHEADER__ - /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ - void setSize (const int w, const int h) throw(); +/** + Represents a key press, including any modifier keys that are needed. - /** Changes all the rectangle's co-ordinates. */ - void setBounds (const int newX, const int newY, - const int newWidth, const int newHeight) throw(); + E.g. a KeyPress might represent CTRL+C, SHIFT+ALT+H, Spacebar, Escape, etc. - /** Changes the rectangle's width */ - void setWidth (const int newWidth) throw(); + @see Component, KeyListener, Button::addShortcut, KeyPressMappingManager +*/ +class JUCE_API KeyPress +{ +public: - /** Changes the rectangle's height */ - void setHeight (const int newHeight) throw(); + /** Creates an (invalid) KeyPress. - /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. - If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. + @see isValid */ - void setLeft (const int newLeft) throw(); + KeyPress() throw(); - /** Moves the y position, adjusting the height so that the bottom edge remains in the same place. - If the y is moved to be below the current bottom edge, the height will be set to zero. - */ - void setTop (const int newTop) throw(); + /** Creates a KeyPress for a key and some modifiers. - /** Adjusts the width so that the right-hand edge of the rectangle has this new value. - If the new right is below the current X value, the X will be pushed down to match it. - @see getRight + e.g. + CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier) + SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier) + + @param keyCode a code that represents the key - this value must be + one of special constants listed in this class, or an + 8-bit character code such as a letter (case is ignored), + digit or a simple key like "," or ".". Note that this + isn't the same as the textCharacter parameter, so for example + a keyCode of 'a' and a shift-key modifier should have a + textCharacter value of 'A'. + @param modifiers the modifiers to associate with the keystroke + @param textCharacter the character that would be printed if someone typed + this keypress into a text editor. This value may be + null if the keypress is a non-printing character + @see getKeyCode, isKeyCode, getModifiers */ - void setRight (const int newRight) throw(); + KeyPress (const int keyCode, + const ModifierKeys& modifiers, + const juce_wchar textCharacter) throw(); - /** Adjusts the height so that the bottom edge of the rectangle has this new value. - If the new bottom is lower than the current Y value, the Y will be pushed down to match it. - @see getBottom + /** Creates a keypress with a keyCode but no modifiers or text character. */ - void setBottom (const int newBottom) throw(); + KeyPress (const int keyCode) throw(); - /** Moves the rectangle's position by adding amount to its x and y co-ordinates. */ - void translate (const int deltaX, - const int deltaY) throw(); + /** Creates a copy of another KeyPress. */ + KeyPress (const KeyPress& other) throw(); - /** Returns a rectangle which is the same as this one moved by a given amount. */ - const Rectangle translated (const int deltaX, - const int deltaY) const throw(); + /** Copies this KeyPress from another one. */ + const KeyPress& operator= (const KeyPress& other) throw(); - /** Expands the rectangle by a given amount. + /** Compares two KeyPress objects. */ + bool operator== (const KeyPress& other) const throw(); - Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). - @see expanded, reduce, reduced - */ - void expand (const int deltaX, - const int deltaY) throw(); + /** Compares two KeyPress objects. */ + bool operator!= (const KeyPress& other) const throw(); - /** Returns a rectangle that is larger than this one by a given amount. + /** Returns true if this is a valid KeyPress. - Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). - @see expand, reduce, reduced + A null keypress can be created by the default constructor, in case it's + needed. */ - const Rectangle expanded (const int deltaX, - const int deltaY) const throw(); + bool isValid() const throw() { return keyCode != 0; } - /** Shrinks the rectangle by a given amount. + /** Returns the key code itself. - Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). - @see reduced, expand, expanded + This will either be one of the special constants defined in this class, + or an 8-bit character code. */ - void reduce (const int deltaX, - const int deltaY) throw(); + int getKeyCode() const throw() { return keyCode; } - /** Returns a rectangle that is smaller than this one by a given amount. + /** Returns the key modifiers. - Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). - @see reduce, expand, expanded + @see ModifierKeys */ - const Rectangle reduced (const int deltaX, - const int deltaY) const throw(); + const ModifierKeys getModifiers() const throw() { return mods; } - /** Returns true if the two rectangles are identical. */ - bool operator== (const Rectangle& other) const throw(); + /** Returns the character that is associated with this keypress. - /** Returns true if the two rectangles are not identical. */ - bool operator!= (const Rectangle& other) const throw(); + This is the character that you'd expect to see printed if you press this + keypress in a text editor or similar component. + */ + juce_wchar getTextCharacter() const throw() { return textCharacter; } - /** Returns true if this co-ordinate is inside the rectangle. */ - bool contains (const int x, const int y) const throw(); + /** Checks whether the KeyPress's key is the same as the one provided, without checking + the modifiers. - /** Returns true if this other rectangle is completely inside this one. */ - bool contains (const Rectangle& other) const throw(); + The values for key codes can either be one of the special constants defined in + this class, or an 8-bit character code. - /** Returns true if any part of another rectangle overlaps this one. */ - bool intersects (const Rectangle& other) const throw(); + @see getKeyCode + */ + bool isKeyCode (const int keyCodeToCompare) const throw() { return keyCode == keyCodeToCompare; } - /** Returns the region that is the overlap between this and another rectangle. + /** Converts a textual key description to a KeyPress. - If the two rectangles don't overlap, the rectangle returned will be empty. - */ - const Rectangle getIntersection (const Rectangle& other) const throw(); + This attempts to decode a textual version of a keypress, e.g. "CTRL + C" or "SPACE". - /** Clips a rectangle so that it lies only within this one. + This isn't designed to cope with any kind of input, but should be given the + strings that are created by the getTextDescription() method. - This is a non-static version of intersectRectangles(). + If the string can't be parsed, the object returned will be invalid. - Returns false if the two regions didn't overlap. + @see getTextDescription */ - bool intersectRectangle (int& x, int& y, int& w, int& h) const throw(); + static const KeyPress createFromDescription (const String& textVersion) throw(); - /** Returns the smallest rectangle that contains both this one and the one - passed-in. - */ - const Rectangle getUnion (const Rectangle& other) const throw(); + /** Creates a textual description of the key combination. - /** If this rectangle merged with another one results in a simple rectangle, this - will set this rectangle to the result, and return true. + e.g. "CTRL + C" or "DELETE". - Returns false and does nothing to this rectangle if the two rectangles don't overlap, - or if they form a complex region. + To store a keypress in a file, use this method, along with createFromDescription() + to retrieve it later. */ - bool enlargeIfAdjacent (const Rectangle& other) throw(); + const String getTextDescription() const throw(); - /** If after removing another rectangle from this one the result is a simple rectangle, - this will set this object's bounds to be the result, and return true. + /** Checks whether the user is currently holding down the keys that make up this + KeyPress. - Returns false and does nothing to this rectangle if the two rectangles don't overlap, - or if removing the other one would form a complex region. + Note that this will return false if any extra modifier keys are + down - e.g. if the keypress is CTRL+X and the user is actually holding CTRL+ALT+x + then it will be false. */ - bool reduceIfPartlyContainedIn (const Rectangle& other) throw(); - - /** Static utility to intersect two sets of rectangular co-ordinates. + bool isCurrentlyDown() const throw(); - Returns false if the two regions didn't overlap. + /** Checks whether a particular key is held down, irrespective of modifiers. - @see intersectRectangle + The values for key codes can either be one of the special constants defined in + this class, or an 8-bit character code. */ - static bool intersectRectangles (int& x1, int& y1, int& w1, int& h1, - int x2, int y2, int w2, int h2) throw(); + static bool isKeyCurrentlyDown (int keyCode) throw(); - /** Creates a string describing this rectangle. + // Key codes + // + // Note that the actual values of these are platform-specific and may change + // without warning, so don't store them anywhere as constants. For persisting/retrieving + // KeyPress objects, use getTextDescription() and createFromDescription() instead. + // - The string will be of the form "x y width height", e.g. "100 100 400 200". + static const int spaceKey; /**< key-code for the space bar */ + static const int escapeKey; /**< key-code for the escape key */ + static const int returnKey; /**< key-code for the return key*/ + static const int tabKey; /**< key-code for the tab key*/ - Coupled with the fromString() method, this is very handy for things like - storing rectangles (particularly component positions) in XML attributes. + static const int deleteKey; /**< key-code for the delete key (not backspace) */ + static const int backspaceKey; /**< key-code for the backspace key */ + static const int insertKey; /**< key-code for the insert key */ - @see fromString - */ - const String toString() const throw(); + static const int upKey; /**< key-code for the cursor-up key */ + static const int downKey; /**< key-code for the cursor-down key */ + static const int leftKey; /**< key-code for the cursor-left key */ + static const int rightKey; /**< key-code for the cursor-right key */ + static const int pageUpKey; /**< key-code for the page-up key */ + static const int pageDownKey; /**< key-code for the page-down key */ + static const int homeKey; /**< key-code for the home key */ + static const int endKey; /**< key-code for the end key */ - /** Parses a string containing a rectangle's details. + static const int F1Key; /**< key-code for the F1 key */ + static const int F2Key; /**< key-code for the F2 key */ + static const int F3Key; /**< key-code for the F3 key */ + static const int F4Key; /**< key-code for the F4 key */ + static const int F5Key; /**< key-code for the F5 key */ + static const int F6Key; /**< key-code for the F6 key */ + static const int F7Key; /**< key-code for the F7 key */ + static const int F8Key; /**< key-code for the F8 key */ + static const int F9Key; /**< key-code for the F9 key */ + static const int F10Key; /**< key-code for the F10 key */ + static const int F11Key; /**< key-code for the F11 key */ + static const int F12Key; /**< key-code for the F12 key */ + static const int F13Key; /**< key-code for the F13 key */ + static const int F14Key; /**< key-code for the F14 key */ + static const int F15Key; /**< key-code for the F15 key */ + static const int F16Key; /**< key-code for the F16 key */ - The string should contain 4 integer tokens, in the form "x y width height". They - can be comma or whitespace separated. + static const int numberPad0; /**< key-code for the 0 on the numeric keypad. */ + static const int numberPad1; /**< key-code for the 1 on the numeric keypad. */ + static const int numberPad2; /**< key-code for the 2 on the numeric keypad. */ + static const int numberPad3; /**< key-code for the 3 on the numeric keypad. */ + static const int numberPad4; /**< key-code for the 4 on the numeric keypad. */ + static const int numberPad5; /**< key-code for the 5 on the numeric keypad. */ + static const int numberPad6; /**< key-code for the 6 on the numeric keypad. */ + static const int numberPad7; /**< key-code for the 7 on the numeric keypad. */ + static const int numberPad8; /**< key-code for the 8 on the numeric keypad. */ + static const int numberPad9; /**< key-code for the 9 on the numeric keypad. */ - This method is intended to go with the toString() method, to form an easy way - of saving/loading rectangles as strings. + static const int numberPadAdd; /**< key-code for the add sign on the numeric keypad. */ + static const int numberPadSubtract; /**< key-code for the subtract sign on the numeric keypad. */ + static const int numberPadMultiply; /**< key-code for the multiply sign on the numeric keypad. */ + static const int numberPadDivide; /**< key-code for the divide sign on the numeric keypad. */ + static const int numberPadSeparator; /**< key-code for the comma on the numeric keypad. */ + static const int numberPadDecimalPoint; /**< key-code for the decimal point sign on the numeric keypad. */ + static const int numberPadEquals; /**< key-code for the equals key on the numeric keypad. */ + static const int numberPadDelete; /**< key-code for the delete key on the numeric keypad. */ - @see toString - */ - static const Rectangle fromString (const String& stringVersion); + static const int playKey; /**< key-code for a multimedia 'play' key, (not all keyboards will have one) */ + static const int stopKey; /**< key-code for a multimedia 'stop' key, (not all keyboards will have one) */ + static const int fastForwardKey; /**< key-code for a multimedia 'fast-forward' key, (not all keyboards will have one) */ + static const int rewindKey; /**< key-code for a multimedia 'rewind' key, (not all keyboards will have one) */ juce_UseDebuggingNewOperator private: - friend class RectangleList; - int x, y, w, h; + + int keyCode; + ModifierKeys mods; + juce_wchar textCharacter; }; -#endif // __JUCE_RECTANGLE_JUCEHEADER__ -/********* End of inlined file: juce_Rectangle.h *********/ +#endif // __JUCE_KEYPRESS_JUCEHEADER__ +/********* End of inlined file: juce_KeyPress.h *********/ -/********* Start of inlined file: juce_Justification.h *********/ -#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ -#define __JUCE_JUSTIFICATION_JUCEHEADER__ +class Component; /** - Represents a type of justification to be used when positioning graphical items. + Receives callbacks when keys are pressed. - e.g. it indicates whether something should be placed top-left, top-right, - centred, etc. + You can add a key listener to a component to be informed when that component + gets key events. See the Component::addListener method for more details. - It is used in various places wherever this kind of information is needed. + @see KeyPress, Component::addKeyListener, KeyPressMappingManager */ -class JUCE_API Justification +class JUCE_API KeyListener { public: + /** Destructor. */ + virtual ~KeyListener() {} - /** Creates a Justification object using a combination of flags. */ - inline Justification (const int flags_) throw() : flags (flags_) {} - - /** Creates a copy of another Justification object. */ - Justification (const Justification& other) throw(); + /** Called to indicate that a key has been pressed. - /** Copies another Justification object. */ - const Justification& operator= (const Justification& other) throw(); + If your implementation returns true, then the key event is considered to have + been consumed, and will not be passed on to any other components. If it returns + false, then the key will be passed to other components that might want to use it. - /** Returns the raw flags that are set for this Justification object. */ - inline int getFlags() const throw() { return flags; } - - /** Tests a set of flags for this object. - - @returns true if any of the flags passed in are set on this object. + @param key the keystroke, including modifier keys + @param originatingComponent the component that received the key event + @see keyStateChanged, Component::keyPressed */ - inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } + virtual bool keyPressed (const KeyPress& key, + Component* originatingComponent) = 0; - /** Returns just the flags from this object that deal with vertical layout. */ - int getOnlyVerticalFlags() const throw(); + /** Called when any key is pressed or released. - /** Returns just the flags from this object that deal with horizontal layout. */ - int getOnlyHorizontalFlags() const throw(); + When this is called, classes that might be interested in + the state of one or more keys can use KeyPress::isKeyCurrentlyDown() to + check whether their key has changed. - /** Adjusts the position of a rectangle to fit it into a space. + If your implementation returns true, then the key event is considered to have + been consumed, and will not be passed on to any other components. If it returns + false, then the key will be passed to other components that might want to use it. - The (x, y) position of the rectangle will be updated to position it inside the - given space according to the justification flags. + @param originatingComponent the component that received the key event + @param isKeyDown true if a key is being pressed, false if one is being released + @see KeyPress, Component::keyStateChanged */ - void applyToRectangle (int& x, int& y, - const int w, const int h, - const int spaceX, const int spaceY, - const int spaceW, const int spaceH) const throw(); - - /** Flag values that can be combined and used in the constructor. */ - enum - { - - /** Indicates that the item should be aligned against the left edge of the available space. */ - left = 1, - - /** Indicates that the item should be aligned against the right edge of the available space. */ - right = 2, - - /** Indicates that the item should be placed in the centre between the left and right - sides of the available space. */ - horizontallyCentred = 4, - - /** Indicates that the item should be aligned against the top edge of the available space. */ - top = 8, + virtual bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); +}; - /** Indicates that the item should be aligned against the bottom edge of the available space. */ - bottom = 16, +#endif // __JUCE_KEYLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_KeyListener.h *********/ - /** Indicates that the item should be placed in the centre between the top and bottom - sides of the available space. */ - verticallyCentred = 32, +/********* Start of inlined file: juce_KeyboardFocusTraverser.h *********/ +#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ +#define __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ - /** Indicates that lines of text should be spread out to fill the maximum width - available, so that both margins are aligned vertically. - */ - horizontallyJustified = 64, +class Component; - /** Indicates that the item should be centred vertically and horizontally. +/** + Controls the order in which focus moves between components. - This is equivalent to (horizontallyCentred | verticallyCentred) - */ - centred = 36, + The default algorithm used by this class to work out the order of traversal + is as follows: + - if two components both have an explicit focus order specified, then the + one with the lowest number comes first (see the Component::setExplicitFocusOrder() + method). + - any component with an explicit focus order greater than 0 comes before ones + that don't have an order specified. + - any unspecified components are traversed in a left-to-right, then top-to-bottom + order. - /** Indicates that the item should be centred vertically but placed on the left hand side. + If you need traversal in a more customised way, you can create a subclass + of KeyboardFocusTraverser that uses your own algorithm, and use + Component::createFocusTraverser() to create it. - This is equivalent to (left | verticallyCentred) - */ - centredLeft = 33, + @see Component::setExplicitFocusOrder, Component::createFocusTraverser +*/ +class JUCE_API KeyboardFocusTraverser +{ +public: + KeyboardFocusTraverser(); - /** Indicates that the item should be centred vertically but placed on the right hand side. + /** Destructor. */ + virtual ~KeyboardFocusTraverser(); - This is equivalent to (right | verticallyCentred) - */ - centredRight = 34, + /** Returns the component that should be given focus after the specified one + when moving "forwards". - /** Indicates that the item should be centred horizontally and placed at the top. + The default implementation will return the next component which is to the + right of or below this one. - This is equivalent to (horizontallyCentred | top) - */ - centredTop = 12, + This may return 0 if there's no suitable candidate. + */ + virtual Component* getNextComponent (Component* current); - /** Indicates that the item should be centred horizontally and placed at the bottom. + /** Returns the component that should be given focus after the specified one + when moving "backwards". - This is equivalent to (horizontallyCentred | bottom) - */ - centredBottom = 20, + The default implementation will return the next component which is to the + left of or above this one. - /** Indicates that the item should be placed in the top-left corner. + This may return 0 if there's no suitable candidate. + */ + virtual Component* getPreviousComponent (Component* current); - This is equivalent to (left | top) - */ - topLeft = 9, + /** Returns the component that should receive focus be default within the given + parent component. - /** Indicates that the item should be placed in the top-right corner. + The default implementation will just return the foremost child component that + wants focus. - This is equivalent to (right | top) - */ - topRight = 10, + This may return 0 if there's no suitable candidate. + */ + virtual Component* getDefaultComponent (Component* parentComponent); +}; - /** Indicates that the item should be placed in the bottom-left corner. +#endif // __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ +/********* End of inlined file: juce_KeyboardFocusTraverser.h *********/ - This is equivalent to (left | bottom) - */ - bottomLeft = 17, +/********* Start of inlined file: juce_ImageEffectFilter.h *********/ +#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ +#define __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ - /** Indicates that the item should be placed in the bottom-left corner. +/********* Start of inlined file: juce_Graphics.h *********/ +#ifndef __JUCE_GRAPHICS_JUCEHEADER__ +#define __JUCE_GRAPHICS_JUCEHEADER__ - This is equivalent to (right | bottom) - */ - bottomRight = 18 - }; +/********* Start of inlined file: juce_Font.h *********/ +#ifndef __JUCE_FONT_JUCEHEADER__ +#define __JUCE_FONT_JUCEHEADER__ -private: +/********* Start of inlined file: juce_Typeface.h *********/ +#ifndef __JUCE_TYPEFACE_JUCEHEADER__ +#define __JUCE_TYPEFACE_JUCEHEADER__ - int flags; -}; +/********* Start of inlined file: juce_Path.h *********/ +#ifndef __JUCE_PATH_JUCEHEADER__ +#define __JUCE_PATH_JUCEHEADER__ -#endif // __JUCE_JUSTIFICATION_JUCEHEADER__ -/********* End of inlined file: juce_Justification.h *********/ +/********* Start of inlined file: juce_AffineTransform.h *********/ +#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ +#define __JUCE_AFFINETRANSFORM_JUCEHEADER__ -/********* Start of inlined file: juce_EdgeTable.h *********/ -#ifndef __JUCE_EDGETABLE_JUCEHEADER__ -#define __JUCE_EDGETABLE_JUCEHEADER__ +/** + Represents a 2D affine-transformation matrix. -class Path; -class Image; + An affine transformation is a transformation such as a rotation, scale, shear, + resize or translation. -/** - A table of horizontal scan-line segments - used for rasterising Paths. + These are used for various 2D transformation tasks, e.g. with Path objects. - @see Path, Graphics + @see Path, Point, Line */ -class JUCE_API EdgeTable +class JUCE_API AffineTransform { public: - /** Creates an edge table containing a path. + /** Creates an identity transform. */ + AffineTransform() throw(); - A table is created with a fixed vertical range, and only sections of the path - which lie within this range will be added to the table. + /** Creates a copy of another transform. */ + AffineTransform (const AffineTransform& other) throw(); - @param clipLimits only the region of the path that lies within this area will be added - @param pathToAdd the path to add to the table - @param transform a transform to apply to the path being added - */ - EdgeTable (const Rectangle& clipLimits, - const Path& pathToAdd, - const AffineTransform& transform) throw(); + /** Creates a transform from a set of raw matrix values. - /** Creates an edge table containing a rectangle. - */ - EdgeTable (const Rectangle& rectangleToAdd) throw(); + The resulting matrix is: - /** Creates an edge table containing a rectangle. + (mat00 mat01 mat02) + (mat10 mat11 mat12) + ( 0 0 1 ) */ - EdgeTable (const float x, const float y, - const float w, const float h) throw(); + AffineTransform (const float mat00, const float mat01, const float mat02, + const float mat10, const float mat11, const float mat12) throw(); - /** Creates a copy of another edge table. */ - EdgeTable (const EdgeTable& other) throw(); + /** Copies from another AffineTransform object */ + const AffineTransform& operator= (const AffineTransform& other) throw(); - /** Copies from another edge table. */ - const EdgeTable& operator= (const EdgeTable& other) throw(); + /** Compares two transforms. */ + bool operator== (const AffineTransform& other) const throw(); - /** Destructor. */ - ~EdgeTable() throw(); + /** Compares two transforms. */ + bool operator!= (const AffineTransform& other) const throw(); - void clipToRectangle (const Rectangle& r) throw(); - void excludeRectangle (const Rectangle& r) throw(); - void clipToEdgeTable (const EdgeTable& other); - void clipLineToMask (int x, int y, uint8* mask, int maskStride, int numPixels) throw(); - bool isEmpty() throw(); - const Rectangle& getMaximumBounds() const throw() { return bounds; } - void translate (float dx, int dy) throw(); + /** A ready-to-use identity transform, which you can use to append other + transformations to. - /** Reduces the amount of space the table has allocated. + e.g. @code + AffineTransform myTransform = AffineTransform::identity.rotated (.5f) + .scaled (2.0f); - This will shrink the table down to use as little memory as possible - useful for - read-only tables that get stored and re-used for rendering. + @endcode */ - void optimiseTable() throw(); + static const AffineTransform identity; - /** Iterates the lines in the table, for rendering. + /** Transforms a 2D co-ordinate using this matrix. */ + void transformPoint (float& x, + float& y) const throw(); - This function will iterate each line in the table, and call a user-defined class - to render each pixel or continuous line of pixels that the table contains. + /** Transforms a 2D co-ordinate using this matrix. */ + void transformPoint (double& x, + double& y) const throw(); - @param iterationCallback this templated class must contain the following methods: - @code - inline void setEdgeTableYPos (int y); - inline void handleEdgeTablePixel (int x, int alphaLevel) const; - inline void handleEdgeTableLine (int x, int width, int alphaLevel) const; - @endcode - (these don't necessarily have to be 'const', but it might help it go faster) - */ - template - void iterate (EdgeTableIterationCallback& iterationCallback) const throw() - { - const int* lineStart = table; + /** Returns a new transform which is the same as this one followed by a translation. */ + const AffineTransform translated (const float deltaX, + const float deltaY) const throw(); - for (int y = 0; y < bounds.getHeight(); ++y) - { - const int* line = lineStart; - lineStart += lineStrideElements; - int numPoints = line[0]; + /** Returns a new transform which is a translation. */ + static const AffineTransform translation (const float deltaX, + const float deltaY) throw(); - if (--numPoints > 0) - { - int x = *++line; - jassert ((x >> 8) >= bounds.getX() && (x >> 8) < bounds.getRight()); - int levelAccumulator = 0; + /** Returns a transform which is the same as this one followed by a rotation. - iterationCallback.setEdgeTableYPos (bounds.getY() + y); + The rotation is specified by a number of radians to rotate clockwise, centred around + the origin (0, 0). + */ + const AffineTransform rotated (const float angleInRadians) const throw(); - while (--numPoints >= 0) - { - const int level = *++line; - jassert (((unsigned int) level) < (unsigned int) 256); - const int endX = *++line; - jassert (endX >= x); - const int endOfRun = (endX >> 8); + /** Returns a transform which is the same as this one followed by a rotation about a given point. - if (endOfRun == (x >> 8)) - { - // small segment within the same pixel, so just save it for the next - // time round.. - levelAccumulator += (endX - x) * level; - } - else - { - // plot the fist pixel of this segment, including any accumulated - // levels from smaller segments that haven't been drawn yet - levelAccumulator += (0xff - (x & 0xff)) * level; - levelAccumulator >>= 8; - x >>= 8; + The rotation is specified by a number of radians to rotate clockwise, centred around + the co-ordinates passed in. + */ + const AffineTransform rotated (const float angleInRadians, + const float pivotX, + const float pivotY) const throw(); - if (levelAccumulator > 0) - { - if (levelAccumulator >> 8) - levelAccumulator = 0xff; + /** Returns a new transform which is a rotation about (0, 0). */ + static const AffineTransform rotation (const float angleInRadians) throw(); - iterationCallback.handleEdgeTablePixel (x, levelAccumulator); - } + /** Returns a new transform which is a rotation about a given point. */ + static const AffineTransform rotation (const float angleInRadians, + const float pivotX, + const float pivotY) throw(); - // if there's a run of similar pixels, do it all in one go.. - if (level > 0) - { - jassert (endOfRun <= bounds.getRight()); - const int numPix = endOfRun - ++x; + /** Returns a transform which is the same as this one followed by a re-scaling. - if (numPix > 0) - iterationCallback.handleEdgeTableLine (x, numPix, level); - } + The scaling is centred around the origin (0, 0). + */ + const AffineTransform scaled (const float factorX, + const float factorY) const throw(); - // save the bit at the end to be drawn next time round the loop. - levelAccumulator = (endX & 0xff) * level; - } + /** Returns a new transform which is a re-scale about the origin. */ + static const AffineTransform scale (const float factorX, + const float factorY) throw(); - x = endX; - } + /** Returns a transform which is the same as this one followed by a shear. - if (levelAccumulator > 0) - { - levelAccumulator >>= 8; - if (levelAccumulator >> 8) - levelAccumulator = 0xff; + The shear is centred around the origin (0, 0). + */ + const AffineTransform sheared (const float shearX, + const float shearY) const throw(); - x >>= 8; - jassert (x >= bounds.getX() && x < bounds.getRight()); - iterationCallback.handleEdgeTablePixel (x, levelAccumulator); - } - } - } - } + /** Returns a matrix which is the inverse operation of this one. - juce_UseDebuggingNewOperator + Some matrices don't have an inverse - in this case, the method will just return + an identity transform. + */ + const AffineTransform inverted() const throw(); -private: - // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc - int* table; - Rectangle bounds; - int maxEdgesPerLine, lineStrideElements; - bool needToCheckEmptinesss; + /** Returns the result of concatenating another transformation after this one. */ + const AffineTransform followedBy (const AffineTransform& other) const throw(); - void addEdgePoint (const int x, const int y, const int winding) throw(); - void remapTableForNumEdges (const int newNumEdgesPerLine) throw(); - void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); -}; + /** Returns true if this transform has no effect on points. */ + bool isIdentity() const throw(); -#endif // __JUCE_EDGETABLE_JUCEHEADER__ -/********* End of inlined file: juce_EdgeTable.h *********/ + /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */ + bool isSingularity() const throw(); -class Image; + /** Returns true if the transform only translates, and doesn't scale or rotate the + points. */ + bool isOnlyTranslation() const throw(); -/** - A path is a sequence of lines and curves that may either form a closed shape - or be open-ended. + /** If this transform is only a translation, this returns the X offset. + @see isOnlyTranslation + */ + float getTranslationX() const throw() { return mat02; } - To use a path, you can create an empty one, then add lines and curves to it - to create shapes, then it can be rendered by a Graphics context or used - for geometric operations. + /** If this transform is only a translation, this returns the X offset. + @see isOnlyTranslation + */ + float getTranslationY() const throw() { return mat12; } - e.g. @code - Path myPath; + juce_UseDebuggingNewOperator - myPath.startNewSubPath (10.0f, 10.0f); // move the current position to (10, 10) - myPath.lineTo (100.0f, 200.0f); // draw a line from here to (100, 200) - myPath.quadraticTo (0.0f, 150.0f, 5.0f, 50.0f); // draw a curve that ends at (5, 50) - myPath.closeSubPath(); // close the subpath with a line back to (10, 10) + /* The transform matrix is: - // add an ellipse as well, which will form a second sub-path within the path.. - myPath.addEllipse (50.0f, 50.0f, 40.0f, 30.0f); + (mat00 mat01 mat02) + (mat10 mat11 mat12) + ( 0 0 1 ) + */ + float mat00, mat01, mat02; + float mat10, mat11, mat12; - // double the width of the whole thing.. - myPath.applyTransform (AffineTransform::scale (2.0f, 1.0f)); +private: - // and draw it to a graphics context with a 5-pixel thick outline. - g.strokePath (myPath, PathStrokeType (5.0f)); + const AffineTransform followedBy (const float mat00, const float mat01, const float mat02, + const float mat10, const float mat11, const float mat12) const throw(); +}; - @endcode +#endif // __JUCE_AFFINETRANSFORM_JUCEHEADER__ +/********* End of inlined file: juce_AffineTransform.h *********/ - A path object can actually contain multiple sub-paths, which may themselves - be open or closed. +/********* Start of inlined file: juce_Point.h *********/ +#ifndef __JUCE_POINT_JUCEHEADER__ +#define __JUCE_POINT_JUCEHEADER__ - @see PathFlatteningIterator, PathStrokeType, Graphics +/** + A pair of (x, y) co-ordinates. + + Uses 32-bit floating point accuracy. + + @see Line, Path, AffineTransform */ -class JUCE_API Path +class JUCE_API Point { public: - /** Creates an empty path. */ - Path() throw(); - - /** Creates a copy of another path. */ - Path (const Path& other) throw(); - - /** Destructor. */ - ~Path() throw(); + /** Creates a point with co-ordinates (0, 0). */ + Point() throw(); - /** Copies this path from another one. */ - const Path& operator= (const Path& other) throw(); + /** Creates a copy of another point. */ + Point (const Point& other) throw(); - /** Returns true if the path doesn't contain any lines or curves. */ - bool isEmpty() const throw(); + /** Creates a point from an (x, y) position. */ + Point (const float x, const float y) throw(); - /** Returns the smallest rectangle that contains all points within the path. + /** Copies this point from another one. + @see setXY */ - void getBounds (float& x, float& y, - float& w, float& h) const throw(); + const Point& operator= (const Point& other) throw(); - /** Returns the smallest rectangle that contains all points within the path - after it's been transformed with the given tranasform matrix. - */ - void getBoundsTransformed (const AffineTransform& transform, - float& x, float& y, - float& w, float& h) const throw(); + /** Destructor. */ + ~Point() throw(); - /** Checks whether a point lies within the path. + /** Returns the point's x co-ordinate. */ + inline float getX() const throw() { return x; } - This is only relevent for closed paths (see closeSubPath()), and - may produce false results if used on a path which has open sub-paths. + /** Returns the point's y co-ordinate. */ + inline float getY() const throw() { return y; } - The path's winding rule is taken into account by this method. + /** Changes the point's x and y co-ordinates. */ + void setXY (const float x, + const float y) throw(); - The tolerence parameter is passed to the PathFlatteningIterator that - is used to trace the path - for more info about it, see the notes for - the PathFlatteningIterator constructor. + /** Uses a transform to change the point's co-ordinates. - @see closeSubPath, setUsingNonZeroWinding + @see AffineTransform::transformPoint */ - bool contains (const float x, - const float y, - const float tolerence = 10.0f) const throw(); + void applyTransform (const AffineTransform& transform) throw(); - /** Checks whether a line crosses the path. + juce_UseDebuggingNewOperator - This will return positive if the line crosses any of the paths constituent - lines or curves. It doesn't take into account whether the line is inside - or outside the path, or whether the path is open or closed. +private: + float x, y; +}; - The tolerence parameter is passed to the PathFlatteningIterator that - is used to trace the path - for more info about it, see the notes for - the PathFlatteningIterator constructor. - */ - bool intersectsLine (const float x1, const float y1, - const float x2, const float y2, - const float tolerence = 10.0f) throw(); +#endif // __JUCE_POINT_JUCEHEADER__ +/********* End of inlined file: juce_Point.h *********/ - /** Removes all lines and curves, resetting the path completely. */ - void clear() throw(); +/********* Start of inlined file: juce_Rectangle.h *********/ +#ifndef __JUCE_RECTANGLE_JUCEHEADER__ +#define __JUCE_RECTANGLE_JUCEHEADER__ - /** Begins a new subpath with a given starting position. +/** + A rectangle, specified using integer co-ordinates. - This will move the path's current position to the co-ordinates passed in and - make it ready to draw lines or curves starting from this position. + @see RectangleList, Path, Line, Point +*/ +class JUCE_API Rectangle +{ +public: - After adding whatever lines and curves are needed, you can either - close the current sub-path using closeSubPath() or call startNewSubPath() - to move to a new sub-path, leaving the old one open-ended. + /** Creates a rectangle of zero size. - @see lineTo, quadraticTo, cubicTo, closeSubPath + The default co-ordinates will be (0, 0, 0, 0). */ - void startNewSubPath (const float startX, - const float startY) throw(); - - /** Closes a the current sub-path with a line back to its start-point. + Rectangle() throw(); - When creating a closed shape such as a triangle, don't use 3 lineTo() - calls - instead use two lineTo() calls, followed by a closeSubPath() - to join the final point back to the start. + /** Creates a copy of another rectangle. */ + Rectangle (const Rectangle& other) throw(); - This ensures that closes shapes are recognised as such, and this is - important for tasks like drawing strokes, which needs to know whether to - draw end-caps or not. + /** Creates a rectangle with a given position and size. */ + Rectangle (const int x, const int y, + const int width, const int height) throw(); - @see startNewSubPath, lineTo, quadraticTo, cubicTo, closeSubPath - */ - void closeSubPath() throw(); + /** Creates a rectangle with a given size, and a position of (0, 0). */ + Rectangle (const int width, const int height) throw(); - /** Adds a line from the shape's last position to a new end-point. + /** Destructor. */ + ~Rectangle() throw(); - This will connect the end-point of the last line or curve that was added - to a new point, using a straight line. + /** Returns the x co-ordinate of the rectangle's left-hand-side. */ + inline int getX() const throw() { return x; } - See the class description for an example of how to add lines and curves to a path. + /** Returns the y co-ordinate of the rectangle's top edge. */ + inline int getY() const throw() { return y; } - @see startNewSubPath, quadraticTo, cubicTo, closeSubPath - */ - void lineTo (const float endX, - const float endY) throw(); + /** Returns the width of the rectangle. */ + inline int getWidth() const throw() { return w; } - /** Adds a quadratic bezier curve from the shape's last position to a new position. + /** Returns the height of the rectangle. */ + inline int getHeight() const throw() { return h; } - This will connect the end-point of the last line or curve that was added - to a new point, using a quadratic spline with one control-point. + /** Returns the x co-ordinate of the rectangle's right-hand-side. */ + inline int getRight() const throw() { return x + w; } - See the class description for an example of how to add lines and curves to a path. + /** Returns the y co-ordinate of the rectangle's bottom edge. */ + inline int getBottom() const throw() { return y + h; } - @see startNewSubPath, lineTo, cubicTo, closeSubPath - */ - void quadraticTo (const float controlPointX, - const float controlPointY, - const float endPointX, - const float endPointY) throw(); + /** Returns the x co-ordinate of the rectangle's centre. */ + inline int getCentreX() const throw() { return x + (w >> 1); } - /** Adds a cubic bezier curve from the shape's last position to a new position. + /** Returns the y co-ordinate of the rectangle's centre. */ + inline int getCentreY() const throw() { return y + (h >> 1); } - This will connect the end-point of the last line or curve that was added - to a new point, using a cubic spline with two control-points. + /** Returns true if the rectangle's width and height are both zero or less */ + bool isEmpty() const throw(); - See the class description for an example of how to add lines and curves to a path. + /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ + void setPosition (const int x, const int y) throw(); - @see startNewSubPath, lineTo, quadraticTo, closeSubPath - */ - void cubicTo (const float controlPoint1X, - const float controlPoint1Y, - const float controlPoint2X, - const float controlPoint2Y, - const float endPointX, - const float endPointY) throw(); + /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ + void setSize (const int w, const int h) throw(); - /** Returns the last point that was added to the path by one of the drawing methods. - */ - const Point getCurrentPosition() const; + /** Changes all the rectangle's co-ordinates. */ + void setBounds (const int newX, const int newY, + const int newWidth, const int newHeight) throw(); - /** Adds a rectangle to the path. + /** Changes the rectangle's width */ + void setWidth (const int newWidth) throw(); - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). + /** Changes the rectangle's height */ + void setHeight (const int newHeight) throw(); - @see addRoundedRectangle, addTriangle + /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. + If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. */ - void addRectangle (const float x, const float y, - const float w, const float h) throw(); + void setLeft (const int newLeft) throw(); - /** Adds a rectangle to the path. + /** Moves the y position, adjusting the height so that the bottom edge remains in the same place. + If the y is moved to be below the current bottom edge, the height will be set to zero. + */ + void setTop (const int newTop) throw(); - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). + /** Adjusts the width so that the right-hand edge of the rectangle has this new value. + If the new right is below the current X value, the X will be pushed down to match it. + @see getRight + */ + void setRight (const int newRight) throw(); - @see addRoundedRectangle, addTriangle + /** Adjusts the height so that the bottom edge of the rectangle has this new value. + If the new bottom is lower than the current Y value, the Y will be pushed down to match it. + @see getBottom */ - void addRectangle (const Rectangle& rectangle) throw(); + void setBottom (const int newBottom) throw(); - /** Adds a rectangle with rounded corners to the path. + /** Moves the rectangle's position by adding amount to its x and y co-ordinates. */ + void translate (const int deltaX, + const int deltaY) throw(); - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). + /** Returns a rectangle which is the same as this one moved by a given amount. */ + const Rectangle translated (const int deltaX, + const int deltaY) const throw(); - @see addRectangle, addTriangle - */ - void addRoundedRectangle (const float x, const float y, - const float w, const float h, - float cornerSize) throw(); + /** Expands the rectangle by a given amount. - /** Adds a rectangle with rounded corners to the path. + Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). + @see expanded, reduce, reduced + */ + void expand (const int deltaX, + const int deltaY) throw(); - The rectangle is added as a new sub-path. (Any currently open paths will be - left open). + /** Returns a rectangle that is larger than this one by a given amount. - @see addRectangle, addTriangle + Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). + @see expand, reduce, reduced */ - void addRoundedRectangle (const float x, const float y, - const float w, const float h, - float cornerSizeX, - float cornerSizeY) throw(); - - /** Adds a triangle to the path. + const Rectangle expanded (const int deltaX, + const int deltaY) const throw(); - The triangle is added as a new closed sub-path. (Any currently open paths will be - left open). + /** Shrinks the rectangle by a given amount. - Note that whether the vertices are specified in clockwise or anticlockwise - order will affect how the triangle is filled when it overlaps other - shapes (the winding order setting will affect this of course). + Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). + @see reduced, expand, expanded */ - void addTriangle (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3) throw(); - - /** Adds a quadrilateral to the path. + void reduce (const int deltaX, + const int deltaY) throw(); - The quad is added as a new closed sub-path. (Any currently open paths will be - left open). + /** Returns a rectangle that is smaller than this one by a given amount. - Note that whether the vertices are specified in clockwise or anticlockwise - order will affect how the quad is filled when it overlaps other - shapes (the winding order setting will affect this of course). + Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). + @see reduce, expand, expanded */ - void addQuadrilateral (const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - const float x4, const float y4) throw(); + const Rectangle reduced (const int deltaX, + const int deltaY) const throw(); - /** Adds an ellipse to the path. + /** Returns true if the two rectangles are identical. */ + bool operator== (const Rectangle& other) const throw(); - The shape is added as a new sub-path. (Any currently open paths will be - left open). + /** Returns true if the two rectangles are not identical. */ + bool operator!= (const Rectangle& other) const throw(); - @see addArc - */ - void addEllipse (const float x, const float y, - const float width, const float height) throw(); + /** Returns true if this co-ordinate is inside the rectangle. */ + bool contains (const int x, const int y) const throw(); - /** Adds an elliptical arc to the current path. + /** Returns true if this other rectangle is completely inside this one. */ + bool contains (const Rectangle& other) const throw(); - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. + /** Returns true if any part of another rectangle overlaps this one. */ + bool intersects (const Rectangle& other) const throw(); - @param x the left-hand edge of the rectangle in which the elliptical outline fits - @param y the top edge of the rectangle in which the elliptical outline fits - @param width the width of the rectangle in which the elliptical outline fits - @param height the height of the rectangle in which the elliptical outline fits - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to - draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via - 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. - @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition + /** Returns the region that is the overlap between this and another rectangle. - @see addCentredArc, arcTo, addPieSegment, addEllipse + If the two rectangles don't overlap, the rectangle returned will be empty. */ - void addArc (const float x, const float y, - const float width, const float height, - const float fromRadians, - const float toRadians, - const bool startAsNewSubPath = false) throw(); - - /** Adds an arc which is centred at a given point, and can have a rotation specified. + const Rectangle getIntersection (const Rectangle& other) const throw(); - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. + /** Clips a rectangle so that it lies only within this one. - @param centreX the centre x of the ellipse - @param centreY the centre y of the ellipse - @param radiusX the horizontal radius of the ellipse - @param radiusY the vertical radius of the ellipse - @param rotationOfEllipse an angle by which the whole ellipse should be rotated about its centre, in radians (clockwise) - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to - draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via - 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. - @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, - it will be added to the current sub-path, continuing from the current postition + This is a non-static version of intersectRectangles(). - @see addArc, arcTo + Returns false if the two regions didn't overlap. */ - void addCentredArc (const float centreX, const float centreY, - const float radiusX, const float radiusY, - const float rotationOfEllipse, - const float fromRadians, - const float toRadians, - const bool startAsNewSubPath = false) throw(); + bool intersectRectangle (int& x, int& y, int& w, int& h) const throw(); - /** Adds a "pie-chart" shape to the path. + /** Returns the smallest rectangle that contains both this one and the one + passed-in. + */ + const Rectangle getUnion (const Rectangle& other) const throw(); - The shape is added as a new sub-path. (Any currently open paths will be - left open). + /** If this rectangle merged with another one results in a simple rectangle, this + will set this rectangle to the result, and return true. - Note that when specifying the start and end angles, the curve will be drawn either clockwise - or anti-clockwise according to whether the end angle is greater than the start. This means - that sometimes you may need to use values greater than 2*Pi for the end angle. + Returns false and does nothing to this rectangle if the two rectangles don't overlap, + or if they form a complex region. + */ + bool enlargeIfAdjacent (const Rectangle& other) throw(); - @param x the left-hand edge of the rectangle in which the elliptical outline fits - @param y the top edge of the rectangle in which the elliptical outline fits - @param width the width of the rectangle in which the elliptical outline fits - @param height the height of the rectangle in which the elliptical outline fits - @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the - top-centre of the ellipse) - @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the - top-centre of the ellipse) - @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow - ellipse at its centre, where this value indicates the inner ellipse's size with - respect to the outer one. + /** If after removing another rectangle from this one the result is a simple rectangle, + this will set this object's bounds to be the result, and return true. - @see addArc + Returns false and does nothing to this rectangle if the two rectangles don't overlap, + or if removing the other one would form a complex region. */ - void addPieSegment (const float x, const float y, - const float width, const float height, - const float fromRadians, - const float toRadians, - const float innerCircleProportionalSize); + bool reduceIfPartlyContainedIn (const Rectangle& other) throw(); - /** Adds a line with a specified thickness. + /** Static utility to intersect two sets of rectangular co-ordinates. - The line is added as a new closed sub-path. (Any currently open paths will be - left open). + Returns false if the two regions didn't overlap. - @see addArrow + @see intersectRectangle */ - void addLineSegment (const float startX, const float startY, - const float endX, const float endY, - float lineThickness) throw(); + static bool intersectRectangles (int& x1, int& y1, int& w1, int& h1, + int x2, int y2, int w2, int h2) throw(); - /** Adds a line with an arrowhead on the end. + /** Creates a string describing this rectangle. - The arrow is added as a new closed sub-path. (Any currently open paths will be - left open). - */ - void addArrow (const float startX, const float startY, - const float endX, const float endY, - float lineThickness, - float arrowheadWidth, - float arrowheadLength) throw(); + The string will be of the form "x y width height", e.g. "100 100 400 200". - /** Adds a star shape to the path. + Coupled with the fromString() method, this is very handy for things like + storing rectangles (particularly component positions) in XML attributes. + @see fromString */ - void addStar (const float centreX, - const float centreY, - const int numberOfPoints, - const float innerRadius, - const float outerRadius, - const float startAngle = 0.0f); - - /** Adds a speech-bubble shape to the path. + const String toString() const throw(); - @param bodyX the left of the main body area of the bubble - @param bodyY the top of the main body area of the bubble - @param bodyW the width of the main body area of the bubble - @param bodyH the height of the main body area of the bubble - @param cornerSize the amount by which to round off the corners of the main body rectangle - @param arrowTipX the x position that the tip of the arrow should connect to - @param arrowTipY the y position that the tip of the arrow should connect to - @param whichSide the side to connect the arrow to: 0 = top, 1 = left, 2 = bottom, 3 = right - @param arrowPositionAlongEdgeProportional how far along the edge of the main rectangle the - arrow's base should be - this is a proportional distance between 0 and 1.0 - @param arrowWidth how wide the base of the arrow should be where it joins the main rectangle - */ - void addBubble (float bodyX, float bodyY, - float bodyW, float bodyH, - float cornerSize, - float arrowTipX, - float arrowTipY, - int whichSide, - float arrowPositionAlongEdgeProportional, - float arrowWidth); + /** Parses a string containing a rectangle's details. - /** Adds another path to this one. + The string should contain 4 integer tokens, in the form "x y width height". They + can be comma or whitespace separated. - The new path is added as a new sub-path. (Any currently open paths in this - path will be left open). + This method is intended to go with the toString() method, to form an easy way + of saving/loading rectangles as strings. - @param pathToAppend the path to add + @see toString */ - void addPath (const Path& pathToAppend) throw(); + static const Rectangle fromString (const String& stringVersion); - /** Adds another path to this one, transforming it on the way in. + juce_UseDebuggingNewOperator - The new path is added as a new sub-path, its points being transformed by the given - matrix before being added. +private: + friend class RectangleList; + int x, y, w, h; +}; - @param pathToAppend the path to add - @param transformToApply an optional transform to apply to the incoming vertices - */ - void addPath (const Path& pathToAppend, - const AffineTransform& transformToApply) throw(); +#endif // __JUCE_RECTANGLE_JUCEHEADER__ +/********* End of inlined file: juce_Rectangle.h *********/ - /** Swaps the contents of this path with another one. +/********* Start of inlined file: juce_Justification.h *********/ +#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ +#define __JUCE_JUSTIFICATION_JUCEHEADER__ - The internal data of the two paths is swapped over, so this is much faster than - copying it to a temp variable and back. - */ - void swapWithPath (Path& other); +/** + Represents a type of justification to be used when positioning graphical items. - /** Applies a 2D transform to all the vertices in the path. + e.g. it indicates whether something should be placed top-left, top-right, + centred, etc. - @see AffineTransform, scaleToFit, getTransformToScaleToFit - */ - void applyTransform (const AffineTransform& transform) throw(); + It is used in various places wherever this kind of information is needed. +*/ +class JUCE_API Justification +{ +public: - /** Rescales this path to make it fit neatly into a given space. + /** Creates a Justification object using a combination of flags. */ + inline Justification (const int flags_) throw() : flags (flags_) {} - This is effectively a quick way of calling - applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions)) + /** Creates a copy of another Justification object. */ + Justification (const Justification& other) throw(); - @param x the x position of the rectangle to fit the path inside - @param y the y position of the rectangle to fit the path inside - @param width the width of the rectangle to fit the path inside - @param height the height of the rectangle to fit the path inside - @param preserveProportions if true, it will fit the path into the space without altering its - horizontal/vertical scale ratio; if false, it will distort the - path to fill the specified ratio both horizontally and vertically + /** Copies another Justification object. */ + const Justification& operator= (const Justification& other) throw(); - @see applyTransform, getTransformToScaleToFit + /** Returns the raw flags that are set for this Justification object. */ + inline int getFlags() const throw() { return flags; } + + /** Tests a set of flags for this object. + + @returns true if any of the flags passed in are set on this object. */ - void scaleToFit (const float x, const float y, - const float width, const float height, - const bool preserveProportions) throw(); + inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } - /** Returns a transform that can be used to rescale the path to fit into a given space. + /** Returns just the flags from this object that deal with vertical layout. */ + int getOnlyVerticalFlags() const throw(); - @param x the x position of the rectangle to fit the path inside - @param y the y position of the rectangle to fit the path inside - @param width the width of the rectangle to fit the path inside - @param height the height of the rectangle to fit the path inside - @param preserveProportions if true, it will fit the path into the space without altering its - horizontal/vertical scale ratio; if false, it will distort the - path to fill the specified ratio both horizontally and vertically - @param justificationType if the proportions are preseved, the resultant path may be smaller - than the available rectangle, so this describes how it should be - positioned within the space. - @returns an appropriate transformation + /** Returns just the flags from this object that deal with horizontal layout. */ + int getOnlyHorizontalFlags() const throw(); - @see applyTransform, scaleToFit + /** Adjusts the position of a rectangle to fit it into a space. + The (x, y) position of the rectangle will be updated to position it inside the + given space according to the justification flags. */ - const AffineTransform getTransformToScaleToFit (const float x, const float y, - const float width, const float height, - const bool preserveProportions, - const Justification& justificationType = Justification::centred) const throw(); + void applyToRectangle (int& x, int& y, + const int w, const int h, + const int spaceX, const int spaceY, + const int spaceW, const int spaceH) const throw(); - /** Creates a version of this path where all sharp corners have been replaced by curves. + /** Flag values that can be combined and used in the constructor. */ + enum + { - Wherever two lines meet at an angle, this will replace the corner with a curve - of the given radius. - */ - const Path createPathWithRoundedCorners (const float cornerRadius) const throw(); + /** Indicates that the item should be aligned against the left edge of the available space. */ + left = 1, - /** Changes the winding-rule to be used when filling the path. + /** Indicates that the item should be aligned against the right edge of the available space. */ + right = 2, - If set to true (which is the default), then the path uses a non-zero-winding rule - to determine which points are inside the path. If set to false, it uses an - alternate-winding rule. + /** Indicates that the item should be placed in the centre between the left and right + sides of the available space. */ + horizontallyCentred = 4, - The winding-rule comes into play when areas of the shape overlap other - areas, and determines whether the overlapping regions are considered to be - inside or outside. + /** Indicates that the item should be aligned against the top edge of the available space. */ + top = 8, - Changing this value just sets a flag - it doesn't affect the contents of the - path. + /** Indicates that the item should be aligned against the bottom edge of the available space. */ + bottom = 16, - @see isUsingNonZeroWinding - */ - void setUsingNonZeroWinding (const bool isNonZeroWinding) throw(); + /** Indicates that the item should be placed in the centre between the top and bottom + sides of the available space. */ + verticallyCentred = 32, - /** Returns the flag that indicates whether the path should use a non-zero winding rule. + /** Indicates that lines of text should be spread out to fill the maximum width + available, so that both margins are aligned vertically. + */ + horizontallyJustified = 64, - The default for a new path is true. + /** Indicates that the item should be centred vertically and horizontally. - @see setUsingNonZeroWinding - */ - bool isUsingNonZeroWinding() const throw() { return useNonZeroWinding; } - - /** Iterates the lines and curves that a path contains. - - @see Path, PathFlatteningIterator - */ - class JUCE_API Iterator - { - public: - - Iterator (const Path& path); - ~Iterator(); - - /** Moves onto the next element in the path. - - If this returns false, there are no more elements. If it returns true, - the elementType variable will be set to the type of the current element, - and some of the x and y variables will be filled in with values. + This is equivalent to (horizontallyCentred | verticallyCentred) */ - bool next(); - - enum PathElementType - { - startNewSubPath, /**< For this type, x1 and y1 will be set to indicate the first point in the subpath. */ - lineTo, /**< For this type, x1 and y1 indicate the end point of the line. */ - quadraticTo, /**< For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve. */ - cubicTo, /**< For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic curve. */ - closePath /**< Indicates that the sub-path is being closed. None of the x or y values are valid in this case. */ - }; - - PathElementType elementType; + centred = 36, - float x1, y1, x2, y2, x3, y3; + /** Indicates that the item should be centred vertically but placed on the left hand side. - private: - const Path& path; - int index; + This is equivalent to (left | verticallyCentred) + */ + centredLeft = 33, - Iterator (const Iterator&); - const Iterator& operator= (const Iterator&); - }; + /** Indicates that the item should be centred vertically but placed on the right hand side. - /** Loads a stored path from a data stream. + This is equivalent to (right | verticallyCentred) + */ + centredRight = 34, - The data in the stream must have been written using writePathToStream(). + /** Indicates that the item should be centred horizontally and placed at the top. - Note that this will append the stored path to whatever is currently in - this path, so you might need to call clear() beforehand. + This is equivalent to (horizontallyCentred | top) + */ + centredTop = 12, - @see loadPathFromData, writePathToStream - */ - void loadPathFromStream (InputStream& source); + /** Indicates that the item should be centred horizontally and placed at the bottom. - /** Loads a stored path from a block of data. + This is equivalent to (horizontallyCentred | bottom) + */ + centredBottom = 20, - This is similar to loadPathFromStream(), but just reads from a block - of data. Useful if you're including stored shapes in your code as a - block of static data. + /** Indicates that the item should be placed in the top-left corner. - @see loadPathFromStream, writePathToStream - */ - void loadPathFromData (const unsigned char* const data, - const int numberOfBytes) throw(); + This is equivalent to (left | top) + */ + topLeft = 9, - /** Stores the path by writing it out to a stream. + /** Indicates that the item should be placed in the top-right corner. - After writing out a path, you can reload it using loadPathFromStream(). + This is equivalent to (right | top) + */ + topRight = 10, - @see loadPathFromStream, loadPathFromData - */ - void writePathToStream (OutputStream& destination) const; + /** Indicates that the item should be placed in the bottom-left corner. - /** Creates a string containing a textual representation of this path. - @see restoreFromString - */ - const String toString() const; + This is equivalent to (left | bottom) + */ + bottomLeft = 17, - /** Restores this path from a string that was created with the toString() method. - @see toString() - */ - void restoreFromString (const String& stringVersion); + /** Indicates that the item should be placed in the bottom-left corner. - juce_UseDebuggingNewOperator + This is equivalent to (right | bottom) + */ + bottomRight = 18 + }; private: - friend class PathFlatteningIterator; - friend class Path::Iterator; - ArrayAllocationBase data; - int numElements; - float pathXMin, pathXMax, pathYMin, pathYMax; - bool useNonZeroWinding; - static const float lineMarker; - static const float moveMarker; - static const float quadMarker; - static const float cubicMarker; - static const float closeSubPathMarker; + int flags; }; -#endif // __JUCE_PATH_JUCEHEADER__ -/********* End of inlined file: juce_Path.h *********/ - -class Font; -class CustomTypefaceGlyphInfo; - -/** A typeface represents a size-independent font. +#endif // __JUCE_JUSTIFICATION_JUCEHEADER__ +/********* End of inlined file: juce_Justification.h *********/ - This base class is abstract, but calling createSystemTypefaceFor() will return - a platform-specific subclass that can be used. +/********* Start of inlined file: juce_EdgeTable.h *********/ +#ifndef __JUCE_EDGETABLE_JUCEHEADER__ +#define __JUCE_EDGETABLE_JUCEHEADER__ - The CustomTypeface subclass allow you to build your own typeface, and to - load and save it in the Juce typeface format. +class Path; +class RectangleList; +class Image; - Normally you should never need to deal directly with Typeface objects - the Font - class does everything you typically need for rendering text. +/** + A table of horizontal scan-line segments - used for rasterising Paths. - @see CustomTypeface, Font + @see Path, Graphics */ -class JUCE_API Typeface : public ReferenceCountedObject +class JUCE_API EdgeTable { public: - /** A handy typedef for a pointer to a typeface. */ - typedef ReferenceCountedObjectPtr Ptr; - - /** Returns the name of the typeface. - @see Font::getTypefaceName - */ - const String getName() const throw() { return name; } - - /** Creates a new system typeface. */ - static const Ptr createSystemTypefaceFor (const Font& font); + /** Creates an edge table containing a path. - /** Destructor. */ - virtual ~Typeface(); + A table is created with a fixed vertical range, and only sections of the path + which lie within this range will be added to the table. - /** Returns the ascent of the font, as a proportion of its height. - The height is considered to always be normalised as 1.0, so this will be a - value less that 1.0, indicating the proportion of the font that lies above - its baseline. + @param clipLimits only the region of the path that lies within this area will be added + @param pathToAdd the path to add to the table + @param transform a transform to apply to the path being added */ - virtual float getAscent() const = 0; + EdgeTable (const Rectangle& clipLimits, + const Path& pathToAdd, + const AffineTransform& transform) throw(); - /** Returns the descent of the font, as a proportion of its height. - The height is considered to always be normalised as 1.0, so this will be a - value less that 1.0, indicating the proportion of the font that lies below - its baseline. + /** Creates an edge table containing a rectangle. */ - virtual float getDescent() const = 0; - - /** Measures the width of a line of text. - - The distance returned is based on the font having an normalised height of 1.0. + EdgeTable (const Rectangle& rectangleToAdd) throw(); - You should never need to call this directly! Use Font::getStringWidth() instead! + /** Creates an edge table containing a rectangle list. */ - virtual float getStringWidth (const String& text) = 0; - - /** Converts a line of text into its glyph numbers and their positions. - - The distances returned are based on the font having an normalised height of 1.0. + EdgeTable (const RectangleList& rectanglesToAdd) throw(); - You should never need to call this directly! Use Font::getGlyphPositions() instead! + /** Creates an edge table containing a rectangle. */ - virtual void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets) = 0; + EdgeTable (const float x, const float y, + const float w, const float h) throw(); - /** Returns the outline for a glyph. + /** Creates a copy of another edge table. */ + EdgeTable (const EdgeTable& other) throw(); - The path returned will be normalised to a font height of 1.0. - */ - virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; + /** Copies from another edge table. */ + const EdgeTable& operator= (const EdgeTable& other) throw(); - juce_UseDebuggingNewOperator + /** Destructor. */ + ~EdgeTable() throw(); -protected: - String name; + void clipToRectangle (const Rectangle& r) throw(); + void excludeRectangle (const Rectangle& r) throw(); + void clipToEdgeTable (const EdgeTable& other); + void clipLineToMask (int x, int y, uint8* mask, int maskStride, int numPixels) throw(); + bool isEmpty() throw(); + const Rectangle& getMaximumBounds() const throw() { return bounds; } + void translate (float dx, int dy) throw(); - Typeface (const String& name) throw(); + /** Reduces the amount of space the table has allocated. -private: - Typeface (const Typeface&); - const Typeface& operator= (const Typeface&); -}; + This will shrink the table down to use as little memory as possible - useful for + read-only tables that get stored and re-used for rendering. + */ + void optimiseTable() throw(); -/** A typeface that can be populated with custom glyphs. + /** Iterates the lines in the table, for rendering. - You can create a CustomTypeface if you need one that contains your own glyphs, - or if you need to load a typeface from a Juce-formatted binary stream. + This function will iterate each line in the table, and call a user-defined class + to render each pixel or continuous line of pixels that the table contains. - If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface() - to copy glyphs into this face. + @param iterationCallback this templated class must contain the following methods: + @code + inline void setEdgeTableYPos (int y); + inline void handleEdgeTablePixel (int x, int alphaLevel) const; + inline void handleEdgeTableLine (int x, int width, int alphaLevel) const; + @endcode + (these don't necessarily have to be 'const', but it might help it go faster) + */ + template + void iterate (EdgeTableIterationCallback& iterationCallback) const throw() + { + const int* lineStart = table; - @see Typeface, Font -*/ -class JUCE_API CustomTypeface : public Typeface -{ -public: + for (int y = 0; y < bounds.getHeight(); ++y) + { + const int* line = lineStart; + lineStart += lineStrideElements; + int numPoints = line[0]; - /** Creates a new, empty typeface. */ - CustomTypeface(); + if (--numPoints > 0) + { + int x = *++line; + jassert ((x >> 8) >= bounds.getX() && (x >> 8) < bounds.getRight()); + int levelAccumulator = 0; - /** Loads a typeface from a previously saved stream. - The stream must have been created by writeToStream(). - @see writeToStream - */ - CustomTypeface (InputStream& serialisedTypefaceStream); + iterationCallback.setEdgeTableYPos (bounds.getY() + y); - /** Destructor. */ - ~CustomTypeface(); + while (--numPoints >= 0) + { + const int level = *++line; + jassert (((unsigned int) level) < (unsigned int) 256); + const int endX = *++line; + jassert (endX >= x); + const int endOfRun = (endX >> 8); - /** Resets this typeface, deleting all its glyphs and settings. */ - void clear(); + if (endOfRun == (x >> 8)) + { + // small segment within the same pixel, so just save it for the next + // time round.. + levelAccumulator += (endX - x) * level; + } + else + { + // plot the fist pixel of this segment, including any accumulated + // levels from smaller segments that haven't been drawn yet + levelAccumulator += (0xff - (x & 0xff)) * level; + levelAccumulator >>= 8; + x >>= 8; - /** Sets the vital statistics for the typeface. - @param name the typeface's name - @param ascent the ascent - this is normalised to a height of 1.0 and this is - the value that will be returned by Typeface::getAscent(). The - descent is assumed to be (1.0 - ascent) - @param isBold should be true if the typeface is bold - @param isItalic should be true if the typeface is italic - @param defaultCharacter the character to be used as a replacement if there's - no glyph available for the character that's being drawn - */ - void setCharacteristics (const String& name, const float ascent, - const bool isBold, const bool isItalic, - const juce_wchar defaultCharacter) throw(); + if (levelAccumulator > 0) + { + if (levelAccumulator >> 8) + levelAccumulator = 0xff; - /** Adds a glyph to the typeface. + iterationCallback.handleEdgeTablePixel (x, levelAccumulator); + } - The path that is passed in is normalised so that the font height is 1.0, and its - origin is the anchor point of the character on its baseline. + // if there's a run of similar pixels, do it all in one go.. + if (level > 0) + { + jassert (endOfRun <= bounds.getRight()); + const int numPix = endOfRun - ++x; - The width is the nominal width of the character, and any extra kerning values that - are specified will be added to this width. - */ - void addGlyph (const juce_wchar character, const Path& path, const float width) throw(); + if (numPix > 0) + iterationCallback.handleEdgeTableLine (x, numPix, level); + } - /** Specifies an extra kerning amount to be used between a pair of characters. - The amount will be added to the nominal width of the first character when laying out a string. - */ - void addKerningPair (const juce_wchar char1, const juce_wchar char2, const float extraAmount) throw(); + // save the bit at the end to be drawn next time round the loop. + levelAccumulator = (endX & 0xff) * level; + } - /** Adds a range of glyphs from another typeface. - This will attempt to pull in the paths and kerning information from another typeface and - add it to this one. - */ - void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) throw(); + x = endX; + } - /** Saves this typeface as a Juce-formatted font file. - A CustomTypeface can be created to reload the data that is written - see the CustomTypeface - constructor. - */ - bool writeToStream (OutputStream& outputStream); + if (levelAccumulator > 0) + { + levelAccumulator >>= 8; + if (levelAccumulator >> 8) + levelAccumulator = 0xff; - // The following methods implement the basic Typeface behaviour. - float getAscent() const; - float getDescent() const; - float getStringWidth (const String& text); - void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets); - bool getOutlineForGlyph (int glyphNumber, Path& path); - int getGlyphForCharacter (juce_wchar character); + x >>= 8; + jassert (x >= bounds.getX() && x < bounds.getRight()); + iterationCallback.handleEdgeTablePixel (x, levelAccumulator); + } + } + } + } juce_UseDebuggingNewOperator -protected: - juce_wchar defaultCharacter; - float ascent; - bool isBold, isItalic; - - /** If a subclass overrides this, it can load glyphs into the font on-demand. - When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a - particular character and there's no corresponding glyph, they'll call this - method so that a subclass can try to add that glyph, returning true if it - manages to do so. - */ - virtual bool loadGlyphIfPossible (const juce_wchar characterNeeded); - private: + // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc + HeapBlock table; + Rectangle bounds; + int maxEdgesPerLine, lineStrideElements; + bool needToCheckEmptinesss; - OwnedArray glyphs; - short lookupTable [128]; - - CustomTypeface (const CustomTypeface&); - const CustomTypeface& operator= (const CustomTypeface&); - - CustomTypefaceGlyphInfo* findGlyph (const juce_wchar character, const bool loadIfNeeded) throw(); - CustomTypefaceGlyphInfo* findGlyphSubstituting (const juce_wchar character) throw(); + void addEdgePoint (const int x, const int y, const int winding) throw(); + void remapTableForNumEdges (const int newNumEdgesPerLine) throw(); + void intersectWithEdgeTableLine (const int y, const int* otherLine) throw(); + void sanitiseLevels (const bool useNonZeroWinding) throw(); }; -#endif // __JUCE_TYPEFACE_JUCEHEADER__ -/********* End of inlined file: juce_Typeface.h *********/ +#endif // __JUCE_EDGETABLE_JUCEHEADER__ +/********* End of inlined file: juce_EdgeTable.h *********/ -class LowLevelGraphicsContext; +class Image; /** - Represents a particular font, including its size, style, etc. - - Apart from the typeface to be used, a Font object also dictates whether - the font is bold, italic, underlined, how big it is, and its kerning and - horizontal scale factor. - - @see Typeface -*/ -class JUCE_API Font -{ -public: + A path is a sequence of lines and curves that may either form a closed shape + or be open-ended. - /** A combination of these values is used by the constructor to specify the - style of font to use. - */ - enum FontStyleFlags - { - plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */ - bold = 1, /**< boldens the font. @see setStyleFlags */ - italic = 2, /**< finds an italic version of the font. @see setStyleFlags */ - underlined = 4 /**< underlines the font. @see setStyleFlags */ - }; + To use a path, you can create an empty one, then add lines and curves to it + to create shapes, then it can be rendered by a Graphics context or used + for geometric operations. - /** Creates a sans-serif font in a given size. + e.g. @code + Path myPath; - @param fontHeight the height in pixels (can be fractional) - @param styleFlags the style to use - this can be a combination of the - Font::bold, Font::italic and Font::underlined, or - just Font::plain for the normal style. - @see FontStyleFlags, getDefaultSansSerifFontName - */ - Font (const float fontHeight, - const int styleFlags = plain) throw(); + myPath.startNewSubPath (10.0f, 10.0f); // move the current position to (10, 10) + myPath.lineTo (100.0f, 200.0f); // draw a line from here to (100, 200) + myPath.quadraticTo (0.0f, 150.0f, 5.0f, 50.0f); // draw a curve that ends at (5, 50) + myPath.closeSubPath(); // close the subpath with a line back to (10, 10) - /** Creates a font with a given typeface and parameters. + // add an ellipse as well, which will form a second sub-path within the path.. + myPath.addEllipse (50.0f, 50.0f, 40.0f, 30.0f); - @param typefaceName the name of the typeface to use - @param fontHeight the height in pixels (can be fractional) - @param styleFlags the style to use - this can be a combination of the - Font::bold, Font::italic and Font::underlined, or - just Font::plain for the normal style. - @see FontStyleFlags, getDefaultSansSerifFontName - */ - Font (const String& typefaceName, - const float fontHeight, - const int styleFlags) throw(); + // double the width of the whole thing.. + myPath.applyTransform (AffineTransform::scale (2.0f, 1.0f)); - /** Creates a copy of another Font object. */ - Font (const Font& other) throw(); + // and draw it to a graphics context with a 5-pixel thick outline. + g.strokePath (myPath, PathStrokeType (5.0f)); - /** Creates a font for a typeface. */ - Font (const Typeface::Ptr& typeface) throw(); + @endcode - /** Creates a basic sans-serif font at a default height. + A path object can actually contain multiple sub-paths, which may themselves + be open or closed. - You should use one of the other constructors for creating a font that you're planning - on drawing with - this constructor is here to help initialise objects before changing - the font's settings later. - */ - Font() throw(); + @see PathFlatteningIterator, PathStrokeType, Graphics +*/ +class JUCE_API Path +{ +public: - /** Copies this font from another one. */ - const Font& operator= (const Font& other) throw(); + /** Creates an empty path. */ + Path() throw(); - bool operator== (const Font& other) const throw(); - bool operator!= (const Font& other) const throw(); + /** Creates a copy of another path. */ + Path (const Path& other) throw(); /** Destructor. */ - ~Font() throw(); + ~Path() throw(); - /** Changes the name of the typeface family. + /** Copies this path from another one. */ + const Path& operator= (const Path& other) throw(); - e.g. "Arial", "Courier", etc. + /** Returns true if the path doesn't contain any lines or curves. */ + bool isEmpty() const throw(); - This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), - or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, - but are generic names that are used to represent the various default fonts. - If you need to know the exact typeface name being used, you can call - Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. + /** Returns the smallest rectangle that contains all points within the path. + */ + void getBounds (float& x, float& y, + float& w, float& h) const throw(); - If a suitable font isn't found on the machine, it'll just use a default instead. + /** Returns the smallest rectangle that contains all points within the path + after it's been transformed with the given tranasform matrix. */ - void setTypefaceName (const String& faceName) throw(); + void getBoundsTransformed (const AffineTransform& transform, + float& x, float& y, + float& w, float& h) const throw(); - /** Returns the name of the typeface family that this font uses. + /** Checks whether a point lies within the path. - e.g. "Arial", "Courier", etc. + This is only relevent for closed paths (see closeSubPath()), and + may produce false results if used on a path which has open sub-paths. - This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), - or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, - but are generic names that are used to represent the various default fonts. + The path's winding rule is taken into account by this method. - If you need to know the exact typeface name being used, you can call - Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. - */ - const String& getTypefaceName() const throw() { return font->typefaceName; } + The tolerence parameter is passed to the PathFlatteningIterator that + is used to trace the path - for more info about it, see the notes for + the PathFlatteningIterator constructor. - /** Returns a typeface name that represents the default sans-serif font. + @see closeSubPath, setUsingNonZeroWinding + */ + bool contains (const float x, + const float y, + const float tolerence = 10.0f) const throw(); - This is also the typeface that will be used when a font is created without - specifying any typeface details. + /** Checks whether a line crosses the path. - Note that this method just returns a generic placeholder string that means "the default - sans-serif font" - it's not the actual name of this font. To get the actual name, use - getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). + This will return positive if the line crosses any of the paths constituent + lines or curves. It doesn't take into account whether the line is inside + or outside the path, or whether the path is open or closed. - @see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName + The tolerence parameter is passed to the PathFlatteningIterator that + is used to trace the path - for more info about it, see the notes for + the PathFlatteningIterator constructor. */ - static const String getDefaultSansSerifFontName() throw(); - - /** Returns a typeface name that represents the default sans-serif font. + bool intersectsLine (const float x1, const float y1, + const float x2, const float y2, + const float tolerence = 10.0f) throw(); - Note that this method just returns a generic placeholder string that means "the default - serif font" - it's not the actual name of this font. To get the actual name, use - getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). + /** Removes all lines and curves, resetting the path completely. */ + void clear() throw(); - @see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName - */ - static const String getDefaultSerifFontName() throw(); + /** Begins a new subpath with a given starting position. - /** Returns a typeface name that represents the default sans-serif font. + This will move the path's current position to the co-ordinates passed in and + make it ready to draw lines or curves starting from this position. - Note that this method just returns a generic placeholder string that means "the default - monospaced font" - it's not the actual name of this font. To get the actual name, use - getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). + After adding whatever lines and curves are needed, you can either + close the current sub-path using closeSubPath() or call startNewSubPath() + to move to a new sub-path, leaving the old one open-ended. - @see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName + @see lineTo, quadraticTo, cubicTo, closeSubPath */ - static const String getDefaultMonospacedFontName() throw(); + void startNewSubPath (const float startX, + const float startY) throw(); - /** Returns the typeface names of the default fonts on the current platform. */ - static void getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed) throw(); + /** Closes a the current sub-path with a line back to its start-point. - /** Returns the total height of this font. + When creating a closed shape such as a triangle, don't use 3 lineTo() + calls - instead use two lineTo() calls, followed by a closeSubPath() + to join the final point back to the start. - This is the maximum height, from the top of the ascent to the bottom of the - descenders. + This ensures that closes shapes are recognised as such, and this is + important for tasks like drawing strokes, which needs to know whether to + draw end-caps or not. - @see setHeight, setHeightWithoutChangingWidth, getAscent + @see startNewSubPath, lineTo, quadraticTo, cubicTo, closeSubPath */ - float getHeight() const throw() { return font->height; } + void closeSubPath() throw(); - /** Changes the font's height. + /** Adds a line from the shape's last position to a new end-point. - @see getHeight, setHeightWithoutChangingWidth - */ - void setHeight (float newHeight) throw(); + This will connect the end-point of the last line or curve that was added + to a new point, using a straight line. - /** Changes the font's height without changing its width. + See the class description for an example of how to add lines and curves to a path. - This alters the horizontal scale to compensate for the change in height. + @see startNewSubPath, quadraticTo, cubicTo, closeSubPath */ - void setHeightWithoutChangingWidth (float newHeight) throw(); + void lineTo (const float endX, + const float endY) throw(); - /** Returns the height of the font above its baseline. + /** Adds a quadratic bezier curve from the shape's last position to a new position. - This is the maximum height from the baseline to the top. + This will connect the end-point of the last line or curve that was added + to a new point, using a quadratic spline with one control-point. - @see getHeight, getDescent + See the class description for an example of how to add lines and curves to a path. + + @see startNewSubPath, lineTo, cubicTo, closeSubPath */ - float getAscent() const throw(); + void quadraticTo (const float controlPointX, + const float controlPointY, + const float endPointX, + const float endPointY) throw(); - /** Returns the amount that the font descends below its baseline. + /** Adds a cubic bezier curve from the shape's last position to a new position. - This is calculated as (getHeight() - getAscent()). + This will connect the end-point of the last line or curve that was added + to a new point, using a cubic spline with two control-points. - @see getAscent, getHeight + See the class description for an example of how to add lines and curves to a path. + + @see startNewSubPath, lineTo, quadraticTo, closeSubPath */ - float getDescent() const throw(); + void cubicTo (const float controlPoint1X, + const float controlPoint1Y, + const float controlPoint2X, + const float controlPoint2Y, + const float endPointX, + const float endPointY) throw(); - /** Returns the font's style flags. + /** Returns the last point that was added to the path by one of the drawing methods. + */ + const Point getCurrentPosition() const; - This will return a bitwise-or'ed combination of values from the FontStyleFlags - enum, to describe whether the font is bold, italic, etc. + /** Adds a rectangle to the path. - @see FontStyleFlags + The rectangle is added as a new sub-path. (Any currently open paths will be + left open). + + @see addRoundedRectangle, addTriangle */ - int getStyleFlags() const throw() { return font->styleFlags; } + void addRectangle (const float x, const float y, + const float w, const float h) throw(); - /** Changes the font's style. + /** Adds a rectangle to the path. - @param newFlags a bitwise-or'ed combination of values from the FontStyleFlags - enum, to set the font's properties - @see FontStyleFlags + The rectangle is added as a new sub-path. (Any currently open paths will be + left open). + + @see addRoundedRectangle, addTriangle */ - void setStyleFlags (const int newFlags) throw(); + void addRectangle (const Rectangle& rectangle) throw(); - /** Makes the font bold or non-bold. */ - void setBold (const bool shouldBeBold) throw(); - /** Returns true if the font is bold. */ - bool isBold() const throw(); + /** Adds a rectangle with rounded corners to the path. - /** Makes the font italic or non-italic. */ - void setItalic (const bool shouldBeItalic) throw(); - /** Returns true if the font is italic. */ - bool isItalic() const throw(); + The rectangle is added as a new sub-path. (Any currently open paths will be + left open). - /** Makes the font underlined or non-underlined. */ - void setUnderline (const bool shouldBeUnderlined) throw(); - /** Returns true if the font is underlined. */ - bool isUnderlined() const throw(); + @see addRectangle, addTriangle + */ + void addRoundedRectangle (const float x, const float y, + const float w, const float h, + float cornerSize) throw(); - /** Changes the font's horizontal scale factor. + /** Adds a rectangle with rounded corners to the path. - @param scaleFactor a value of 1.0 is the normal scale, less than this will be - narrower, greater than 1.0 will be stretched out. + The rectangle is added as a new sub-path. (Any currently open paths will be + left open). + + @see addRectangle, addTriangle */ - void setHorizontalScale (const float scaleFactor) throw(); + void addRoundedRectangle (const float x, const float y, + const float w, const float h, + float cornerSizeX, + float cornerSizeY) throw(); - /** Returns the font's horizontal scale. + /** Adds a triangle to the path. - A value of 1.0 is the normal scale, less than this will be narrower, greater - than 1.0 will be stretched out. + The triangle is added as a new closed sub-path. (Any currently open paths will be + left open). - @see setHorizontalScale + Note that whether the vertices are specified in clockwise or anticlockwise + order will affect how the triangle is filled when it overlaps other + shapes (the winding order setting will affect this of course). */ - float getHorizontalScale() const throw() { return font->horizontalScale; } + void addTriangle (const float x1, const float y1, + const float x2, const float y2, + const float x3, const float y3) throw(); - /** Changes the font's kerning. + /** Adds a quadrilateral to the path. - @param extraKerning a multiple of the font's height that will be added - to space between the characters. So a value of zero is - normal spacing, positive values spread the letters out, - negative values make them closer together. + The quad is added as a new closed sub-path. (Any currently open paths will be + left open). + + Note that whether the vertices are specified in clockwise or anticlockwise + order will affect how the quad is filled when it overlaps other + shapes (the winding order setting will affect this of course). */ - void setExtraKerningFactor (const float extraKerning) throw(); + void addQuadrilateral (const float x1, const float y1, + const float x2, const float y2, + const float x3, const float y3, + const float x4, const float y4) throw(); - /** Returns the font's kerning. + /** Adds an ellipse to the path. - This is the extra space added between adjacent characters, as a proportion - of the font's height. + The shape is added as a new sub-path. (Any currently open paths will be + left open). - A value of zero is normal spacing, positive values will spread the letters - out more, and negative values make them closer together. + @see addArc */ - float getExtraKerningFactor() const throw() { return font->kerning; } + void addEllipse (const float x, const float y, + const float width, const float height) throw(); - /** Changes all the font's characteristics with one call. */ - void setSizeAndStyle (float newHeight, - const int newStyleFlags, - const float newHorizontalScale, - const float newKerningAmount) throw(); + /** Adds an elliptical arc to the current path. - /** Returns the total width of a string as it would be drawn using this font. + Note that when specifying the start and end angles, the curve will be drawn either clockwise + or anti-clockwise according to whether the end angle is greater than the start. This means + that sometimes you may need to use values greater than 2*Pi for the end angle. - For a more accurate floating-point result, use getStringWidthFloat(). + @param x the left-hand edge of the rectangle in which the elliptical outline fits + @param y the top edge of the rectangle in which the elliptical outline fits + @param width the width of the rectangle in which the elliptical outline fits + @param height the height of the rectangle in which the elliptical outline fits + @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the + top-centre of the ellipse) + @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the + top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to + draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via + 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. + @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, + it will be added to the current sub-path, continuing from the current postition + + @see addCentredArc, arcTo, addPieSegment, addEllipse */ - int getStringWidth (const String& text) const throw(); + void addArc (const float x, const float y, + const float width, const float height, + const float fromRadians, + const float toRadians, + const bool startAsNewSubPath = false) throw(); - /** Returns the total width of a string as it would be drawn using this font. + /** Adds an arc which is centred at a given point, and can have a rotation specified. - @see getStringWidth - */ - float getStringWidthFloat (const String& text) const throw(); + Note that when specifying the start and end angles, the curve will be drawn either clockwise + or anti-clockwise according to whether the end angle is greater than the start. This means + that sometimes you may need to use values greater than 2*Pi for the end angle. - /** Returns the series of glyph numbers and their x offsets needed to represent a string. + @param centreX the centre x of the ellipse + @param centreY the centre y of the ellipse + @param radiusX the horizontal radius of the ellipse + @param radiusY the vertical radius of the ellipse + @param rotationOfEllipse an angle by which the whole ellipse should be rotated about its centre, in radians (clockwise) + @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the + top-centre of the ellipse) + @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the + top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to + draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via + 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. + @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, + it will be added to the current sub-path, continuing from the current postition - An extra x offset is added at the end of the run, to indicate where the right hand - edge of the last character is. + @see addArc, arcTo */ - void getGlyphPositions (const String& text, Array & glyphs, Array & xOffsets) const throw(); + void addCentredArc (const float centreX, const float centreY, + const float radiusX, const float radiusY, + const float rotationOfEllipse, + const float fromRadians, + const float toRadians, + const bool startAsNewSubPath = false) throw(); - /** Returns the typeface used by this font. + /** Adds a "pie-chart" shape to the path. - Note that the object returned may go out of scope if this font is deleted - or has its style changed. - */ - Typeface* getTypeface() const throw(); + The shape is added as a new sub-path. (Any currently open paths will be + left open). - /** Creates an array of Font objects to represent all the fonts on the system. + Note that when specifying the start and end angles, the curve will be drawn either clockwise + or anti-clockwise according to whether the end angle is greater than the start. This means + that sometimes you may need to use values greater than 2*Pi for the end angle. - If you just need the names of the typefaces, you can also use - findAllTypefaceNames() instead. + @param x the left-hand edge of the rectangle in which the elliptical outline fits + @param y the top edge of the rectangle in which the elliptical outline fits + @param width the width of the rectangle in which the elliptical outline fits + @param height the height of the rectangle in which the elliptical outline fits + @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the + top-centre of the ellipse) + @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the + top-centre of the ellipse) + @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow + ellipse at its centre, where this value indicates the inner ellipse's size with + respect to the outer one. - @param results the array to which new Font objects will be added. + @see addArc */ - static void findFonts (OwnedArray& results) throw(); + void addPieSegment (const float x, const float y, + const float width, const float height, + const float fromRadians, + const float toRadians, + const float innerCircleProportionalSize); - /** Returns a list of all the available typeface names. + /** Adds a line with a specified thickness. - The names returned can be passed into setTypefaceName(). + The line is added as a new closed sub-path. (Any currently open paths will be + left open). - You can use this instead of findFonts() if you only need their names, and not - font objects. + @see addArrow */ - static const StringArray findAllTypefaceNames() throw(); + void addLineSegment (const float startX, const float startY, + const float endX, const float endY, + float lineThickness) throw(); - /** Returns the name of the typeface to be used for rendering glyphs that aren't found - in the requested typeface. + /** Adds a line with an arrowhead on the end. + + The arrow is added as a new closed sub-path. (Any currently open paths will be + left open). */ - static const String getFallbackFontName() throw(); + void addArrow (const float startX, const float startY, + const float endX, const float endY, + float lineThickness, + float arrowheadWidth, + float arrowheadLength) throw(); + + /** Adds a star shape to the path. - /** Sets the (platform-specific) name of the typeface to use to find glyphs that aren't - available in whatever font you're trying to use. */ - static void setFallbackFontName (const String& name) throw(); + void addStar (const float centreX, + const float centreY, + const int numberOfPoints, + const float innerRadius, + const float outerRadius, + const float startAngle = 0.0f); - juce_UseDebuggingNewOperator + /** Adds a speech-bubble shape to the path. -private: + @param bodyX the left of the main body area of the bubble + @param bodyY the top of the main body area of the bubble + @param bodyW the width of the main body area of the bubble + @param bodyH the height of the main body area of the bubble + @param cornerSize the amount by which to round off the corners of the main body rectangle + @param arrowTipX the x position that the tip of the arrow should connect to + @param arrowTipY the y position that the tip of the arrow should connect to + @param whichSide the side to connect the arrow to: 0 = top, 1 = left, 2 = bottom, 3 = right + @param arrowPositionAlongEdgeProportional how far along the edge of the main rectangle the + arrow's base should be - this is a proportional distance between 0 and 1.0 + @param arrowWidth how wide the base of the arrow should be where it joins the main rectangle + */ + void addBubble (float bodyX, float bodyY, + float bodyW, float bodyH, + float cornerSize, + float arrowTipX, + float arrowTipY, + int whichSide, + float arrowPositionAlongEdgeProportional, + float arrowWidth); - friend class FontGlyphAlphaMap; - friend class TypefaceCache; + /** Adds another path to this one. - class SharedFontInternal : public ReferenceCountedObject - { - public: - SharedFontInternal (const String& typefaceName, const float height, const float horizontalScale, - const float kerning, const float ascent, const int styleFlags, - Typeface* const typeface) throw(); - SharedFontInternal (const SharedFontInternal& other) throw(); + The new path is added as a new sub-path. (Any currently open paths in this + path will be left open). - String typefaceName; - float height, horizontalScale, kerning, ascent; - int styleFlags; - Typeface::Ptr typeface; - }; + @param pathToAppend the path to add + */ + void addPath (const Path& pathToAppend) throw(); - ReferenceCountedObjectPtr font; - void dupeInternalIfShared() throw(); -}; + /** Adds another path to this one, transforming it on the way in. -#endif // __JUCE_FONT_JUCEHEADER__ -/********* End of inlined file: juce_Font.h *********/ + The new path is added as a new sub-path, its points being transformed by the given + matrix before being added. -/********* Start of inlined file: juce_PathStrokeType.h *********/ -#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ -#define __JUCE_PATHSTROKETYPE_JUCEHEADER__ + @param pathToAppend the path to add + @param transformToApply an optional transform to apply to the incoming vertices + */ + void addPath (const Path& pathToAppend, + const AffineTransform& transformToApply) throw(); -/** - Describes a type of stroke used to render a solid outline along a path. + /** Swaps the contents of this path with another one. - A PathStrokeType object can be used directly to create the shape of an outline - around a path, and is used by Graphics::strokePath to specify the type of - stroke to draw. + The internal data of the two paths is swapped over, so this is much faster than + copying it to a temp variable and back. + */ + void swapWithPath (Path& other); - @see Path, Graphics::strokePath -*/ -class JUCE_API PathStrokeType -{ -public: + /** Applies a 2D transform to all the vertices in the path. - /** The type of shape to use for the corners between two adjacent line segments. */ - enum JointStyle - { - mitered, /**< Indicates that corners should be drawn with sharp joints. - Note that for angles that curve back on themselves, drawing a - mitre could require extending the point too far away from the - path, so a mitre limit is imposed and any corners that exceed it - are drawn as bevelled instead. */ - curved, /**< Indicates that corners should be drawn as rounded-off. */ - beveled /**< Indicates that corners should be drawn with a line flattening their - outside edge. */ - }; + @see AffineTransform, scaleToFit, getTransformToScaleToFit + */ + void applyTransform (const AffineTransform& transform) throw(); - /** The type shape to use for the ends of lines. */ - enum EndCapStyle - { - butt, /**< Ends of lines are flat and don't extend beyond the end point. */ - square, /**< Ends of lines are flat, but stick out beyond the end point for half - the thickness of the stroke. */ - rounded /**< Ends of lines are rounded-off with a circular shape. */ - }; + /** Rescales this path to make it fit neatly into a given space. - /** Creates a stroke type. + This is effectively a quick way of calling + applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions)) - @param strokeThickness the width of the line to use - @param jointStyle the type of joints to use for corners - @param endStyle the type of end-caps to use for the ends of open paths. + @param x the x position of the rectangle to fit the path inside + @param y the y position of the rectangle to fit the path inside + @param width the width of the rectangle to fit the path inside + @param height the height of the rectangle to fit the path inside + @param preserveProportions if true, it will fit the path into the space without altering its + horizontal/vertical scale ratio; if false, it will distort the + path to fill the specified ratio both horizontally and vertically + + @see applyTransform, getTransformToScaleToFit */ - PathStrokeType (const float strokeThickness, - const JointStyle jointStyle = mitered, - const EndCapStyle endStyle = butt) throw(); + void scaleToFit (const float x, const float y, + const float width, const float height, + const bool preserveProportions) throw(); - /** Createes a copy of another stroke type. */ - PathStrokeType (const PathStrokeType& other) throw(); + /** Returns a transform that can be used to rescale the path to fit into a given space. - /** Copies another stroke onto this one. */ - const PathStrokeType& operator= (const PathStrokeType& other) throw(); + @param x the x position of the rectangle to fit the path inside + @param y the y position of the rectangle to fit the path inside + @param width the width of the rectangle to fit the path inside + @param height the height of the rectangle to fit the path inside + @param preserveProportions if true, it will fit the path into the space without altering its + horizontal/vertical scale ratio; if false, it will distort the + path to fill the specified ratio both horizontally and vertically + @param justificationType if the proportions are preseved, the resultant path may be smaller + than the available rectangle, so this describes how it should be + positioned within the space. + @returns an appropriate transformation - /** Destructor. */ - ~PathStrokeType() throw(); + @see applyTransform, scaleToFit - /** Applies this stroke type to a path and returns the resultant stroke as another Path. + */ + const AffineTransform getTransformToScaleToFit (const float x, const float y, + const float width, const float height, + const bool preserveProportions, + const Justification& justificationType = Justification::centred) const throw(); - @param destPath the resultant stroked outline shape will be copied into this path. - Note that it's ok for the source and destination Paths to be - the same object, so you can easily turn a path into a stroked version - of itself. - @param sourcePath the path to use as the source - @param transform an optional transform to apply to the points from the source path - as they are being used - @param extraAccuracy if this is greater than 1.0, it will subdivide the path to - a higher resolution, which improved the quality if you'll later want - to enlarge the stroked path + /** Creates a version of this path where all sharp corners have been replaced by curves. - @see createDashedStroke + Wherever two lines meet at an angle, this will replace the corner with a curve + of the given radius. */ - void createStrokedPath (Path& destPath, - const Path& sourcePath, - const AffineTransform& transform = AffineTransform::identity, - const float extraAccuracy = 1.0f) const throw(); + const Path createPathWithRoundedCorners (const float cornerRadius) const throw(); - /** Applies this stroke type to a path, creating a dashed line. + /** Changes the winding-rule to be used when filling the path. - This is similar to createStrokedPath, but uses the array passed in to - break the stroke up into a series of dashes. + If set to true (which is the default), then the path uses a non-zero-winding rule + to determine which points are inside the path. If set to false, it uses an + alternate-winding rule. - @param destPath the resultant stroked outline shape will be copied into this path. - Note that it's ok for the source and destination Paths to be - the same object, so you can easily turn a path into a stroked version - of itself. - @param sourcePath the path to use as the source - @param dashLengths An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create - a line of length 2, then skip a length of 3, then add a line of length 4, - skip 5, and keep repeating this pattern. - @param numDashLengths The number of lengths in the dashLengths array. This should really be - an even number, otherwise the pattern will get out of step as it - repeats. - @param transform an optional transform to apply to the points from the source path - as they are being used - @param extraAccuracy if this is greater than 1.0, it will subdivide the path to - a higher resolution, which improved the quality if you'll later want - to enlarge the stroked path + The winding-rule comes into play when areas of the shape overlap other + areas, and determines whether the overlapping regions are considered to be + inside or outside. + + Changing this value just sets a flag - it doesn't affect the contents of the + path. + + @see isUsingNonZeroWinding */ - void createDashedStroke (Path& destPath, - const Path& sourcePath, - const float* dashLengths, - int numDashLengths, - const AffineTransform& transform = AffineTransform::identity, - const float extraAccuracy = 1.0f) const throw(); + void setUsingNonZeroWinding (const bool isNonZeroWinding) throw(); - /** Returns the stroke thickness. */ - float getStrokeThickness() const throw() { return thickness; } + /** Returns the flag that indicates whether the path should use a non-zero winding rule. - /** Returns the joint style. */ - JointStyle getJointStyle() const throw() { return jointStyle; } + The default for a new path is true. - /** Returns the end-cap style. */ - EndCapStyle getEndStyle() const throw() { return endStyle; } + @see setUsingNonZeroWinding + */ + bool isUsingNonZeroWinding() const throw() { return useNonZeroWinding; } - juce_UseDebuggingNewOperator + /** Iterates the lines and curves that a path contains. - /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator== (const PathStrokeType& other) const throw(); + @see Path, PathFlatteningIterator + */ + class JUCE_API Iterator + { + public: - /** Compares the stroke thickness, joint and end styles of two stroke types. */ - bool operator!= (const PathStrokeType& other) const throw(); + Iterator (const Path& path); + ~Iterator(); -private: + /** Moves onto the next element in the path. - float thickness; - JointStyle jointStyle; - EndCapStyle endStyle; -}; + If this returns false, there are no more elements. If it returns true, + the elementType variable will be set to the type of the current element, + and some of the x and y variables will be filled in with values. + */ + bool next(); -#endif // __JUCE_PATHSTROKETYPE_JUCEHEADER__ -/********* End of inlined file: juce_PathStrokeType.h *********/ + enum PathElementType + { + startNewSubPath, /**< For this type, x1 and y1 will be set to indicate the first point in the subpath. */ + lineTo, /**< For this type, x1 and y1 indicate the end point of the line. */ + quadraticTo, /**< For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve. */ + cubicTo, /**< For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic curve. */ + closePath /**< Indicates that the sub-path is being closed. None of the x or y values are valid in this case. */ + }; -/********* Start of inlined file: juce_Line.h *********/ -#ifndef __JUCE_LINE_JUCEHEADER__ -#define __JUCE_LINE_JUCEHEADER__ + PathElementType elementType; -/** - Represents a line, using 32-bit float co-ordinates. + float x1, y1, x2, y2, x3, y3; - This class contains a bunch of useful methods for various geometric - tasks. + private: + const Path& path; + int index; - @see Point, Rectangle, Path, Graphics::drawLine -*/ -class JUCE_API Line -{ -public: + Iterator (const Iterator&); + const Iterator& operator= (const Iterator&); + }; - /** Creates a line, using (0, 0) as its start and end points. */ - Line() throw(); + /** Loads a stored path from a data stream. - /** Creates a copy of another line. */ - Line (const Line& other) throw(); + The data in the stream must have been written using writePathToStream(). - /** Creates a line based on the co-ordinates of its start and end points. */ - Line (const float startX, - const float startY, - const float endX, - const float endY) throw(); + Note that this will append the stored path to whatever is currently in + this path, so you might need to call clear() beforehand. - /** Creates a line from its start and end points. */ - Line (const Point& start, - const Point& end) throw(); + @see loadPathFromData, writePathToStream + */ + void loadPathFromStream (InputStream& source); - /** Copies a line from another one. */ - const Line& operator= (const Line& other) throw(); + /** Loads a stored path from a block of data. - /** Destructor. */ - ~Line() throw(); + This is similar to loadPathFromStream(), but just reads from a block + of data. Useful if you're including stored shapes in your code as a + block of static data. - /** Returns the x co-ordinate of the line's start point. */ - inline float getStartX() const throw() { return startX; } + @see loadPathFromStream, writePathToStream + */ + void loadPathFromData (const unsigned char* const data, + const int numberOfBytes) throw(); - /** Returns the y co-ordinate of the line's start point. */ - inline float getStartY() const throw() { return startY; } + /** Stores the path by writing it out to a stream. - /** Returns the x co-ordinate of the line's end point. */ - inline float getEndX() const throw() { return endX; } + After writing out a path, you can reload it using loadPathFromStream(). - /** Returns the y co-ordinate of the line's end point. */ - inline float getEndY() const throw() { return endY; } + @see loadPathFromStream, loadPathFromData + */ + void writePathToStream (OutputStream& destination) const; - /** Returns the line's start point. */ - const Point getStart() const throw(); + /** Creates a string containing a textual representation of this path. + @see restoreFromString + */ + const String toString() const; - /** Returns the line's end point. */ - const Point getEnd() const throw(); + /** Restores this path from a string that was created with the toString() method. + @see toString() + */ + void restoreFromString (const String& stringVersion); - /** Changes this line's start point */ - void setStart (const float newStartX, - const float newStartY) throw(); + juce_UseDebuggingNewOperator - /** Changes this line's end point */ - void setEnd (const float newEndX, - const float newEndY) throw(); +private: + friend class PathFlatteningIterator; + friend class Path::Iterator; + ArrayAllocationBase data; + int numElements; + float pathXMin, pathXMax, pathYMin, pathYMax; + bool useNonZeroWinding; - /** Changes this line's start point */ - void setStart (const Point& newStart) throw(); + static const float lineMarker; + static const float moveMarker; + static const float quadMarker; + static const float cubicMarker; + static const float closeSubPathMarker; +}; - /** Changes this line's end point */ - void setEnd (const Point& newEnd) throw(); +#endif // __JUCE_PATH_JUCEHEADER__ +/********* End of inlined file: juce_Path.h *********/ - /** Applies an affine transform to the line's start and end points. */ - void applyTransform (const AffineTransform& transform) throw(); +class Font; +class CustomTypefaceGlyphInfo; - /** Returns the length of the line. */ - float getLength() const throw(); +/** A typeface represents a size-independent font. - /** Returns true if the line's start and end x co-ordinates are the same. */ - bool isVertical() const throw(); + This base class is abstract, but calling createSystemTypefaceFor() will return + a platform-specific subclass that can be used. - /** Returns true if the line's start and end y co-ordinates are the same. */ - bool isHorizontal() const throw(); + The CustomTypeface subclass allow you to build your own typeface, and to + load and save it in the Juce typeface format. - /** Returns the line's angle. + Normally you should never need to deal directly with Typeface objects - the Font + class does everything you typically need for rendering text. - This value is the number of radians clockwise from the 3 o'clock direction, - where the line's start point is considered to be at the centre. + @see CustomTypeface, Font +*/ +class JUCE_API Typeface : public ReferenceCountedObject +{ +public: + + /** A handy typedef for a pointer to a typeface. */ + typedef ReferenceCountedObjectPtr Ptr; + + /** Returns the name of the typeface. + @see Font::getTypefaceName */ - float getAngle() const throw(); + const String getName() const throw() { return name; } - /** Compares two lines. */ - bool operator== (const Line& other) const throw(); + /** Creates a new system typeface. */ + static const Ptr createSystemTypefaceFor (const Font& font); - /** Compares two lines. */ - bool operator!= (const Line& other) const throw(); + /** Destructor. */ + virtual ~Typeface(); - /** Finds the intersection between two lines. + /** Returns the ascent of the font, as a proportion of its height. + The height is considered to always be normalised as 1.0, so this will be a + value less that 1.0, indicating the proportion of the font that lies above + its baseline. + */ + virtual float getAscent() const = 0; - @param line the other line - @param intersectionX the x co-ordinate of the point where the lines meet (or - where they would meet if they were infinitely long) - the intersection (if the lines intersect). If the lines - are parallel, this will just be set to the position - of one of the line's endpoints. - @param intersectionY the y co-ordinate of the point where the lines meet - @returns true if the line segments intersect; false if they dont. Even if they - don't intersect, the intersection co-ordinates returned will still - be valid + /** Returns the descent of the font, as a proportion of its height. + The height is considered to always be normalised as 1.0, so this will be a + value less that 1.0, indicating the proportion of the font that lies below + its baseline. */ - bool intersects (const Line& line, - float& intersectionX, - float& intersectionY) const throw(); + virtual float getDescent() const = 0; - /** Returns the location of the point which is a given distance along this line. + /** Measures the width of a line of text. - @param distanceFromStart the distance to move along the line from its - start point. This value can be negative or longer - than the line itself - @see getPointAlongLineProportionally + The distance returned is based on the font having an normalised height of 1.0. + + You should never need to call this directly! Use Font::getStringWidth() instead! */ - const Point getPointAlongLine (const float distanceFromStart) const throw(); + virtual float getStringWidth (const String& text) = 0; - /** Returns a point which is a certain distance along and to the side of this line. + /** Converts a line of text into its glyph numbers and their positions. - This effectively moves a given distance along the line, then another distance - perpendicularly to this, and returns the resulting position. + The distances returned are based on the font having an normalised height of 1.0. - @param distanceFromStart the distance to move along the line from its - start point. This value can be negative or longer - than the line itself - @param perpendicularDistance how far to move sideways from the line. If you're - looking along the line from its start towards its - end, then a positive value here will move to the - right, negative value move to the left. + You should never need to call this directly! Use Font::getGlyphPositions() instead! */ - const Point getPointAlongLine (const float distanceFromStart, - const float perpendicularDistance) const throw(); + virtual void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets) = 0; - /** Returns the location of the point which is a given distance along this line - proportional to the line's length. + /** Returns the outline for a glyph. - @param proportionOfLength the distance to move along the line from its - start point, in multiples of the line's length. - So a value of 0.0 will return the line's start point - and a value of 1.0 will return its end point. (This value - can be negative or greater than 1.0). - @see getPointAlongLine + The path returned will be normalised to a font height of 1.0. */ - const Point getPointAlongLineProportionally (const float proportionOfLength) const throw(); + virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; - /** Returns the smallest distance between this line segment and a given point. + juce_UseDebuggingNewOperator - So if the point is close to the line, this will return the perpendicular - distance from the line; if the point is a long way beyond one of the line's - end-point's, it'll return the straight-line distance to the nearest end-point. +protected: + String name; - @param x x position of the point to test - @param y y position of the point to test - @returns the point's distance from the line - @see getPositionAlongLineOfNearestPoint - */ - float getDistanceFromLine (const float x, - const float y) const throw(); + Typeface (const String& name) throw(); - /** Finds the point on this line which is nearest to a given point, and - returns its position as a proportional position along the line. +private: + Typeface (const Typeface&); + const Typeface& operator= (const Typeface&); +}; - @param x x position of the point to test - @param y y position of the point to test - @returns a value 0 to 1.0 which is the distance along this line from the - line's start to the point which is nearest to the point passed-in. To - turn this number into a position, use getPointAlongLineProportionally(). - @see getDistanceFromLine, getPointAlongLineProportionally - */ - float findNearestPointTo (const float x, - const float y) const throw(); +/** A typeface that can be populated with custom glyphs. - /** Returns true if the given point lies above this line. + You can create a CustomTypeface if you need one that contains your own glyphs, + or if you need to load a typeface from a Juce-formatted binary stream. - The return value is true if the point's y coordinate is less than the y - coordinate of this line at the given x (assuming the line extends infinitely - in both directions). + If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface() + to copy glyphs into this face. + + @see Typeface, Font +*/ +class JUCE_API CustomTypeface : public Typeface +{ +public: + + /** Creates a new, empty typeface. */ + CustomTypeface(); + + /** Loads a typeface from a previously saved stream. + The stream must have been created by writeToStream(). + @see writeToStream */ - bool isPointAbove (const float x, const float y) const throw(); + CustomTypeface (InputStream& serialisedTypefaceStream); - /** Returns a shortened copy of this line. + /** Destructor. */ + ~CustomTypeface(); - This will chop off part of the start of this line by a certain amount, (leaving the - end-point the same), and return the new line. + /** Resets this typeface, deleting all its glyphs and settings. */ + void clear(); + + /** Sets the vital statistics for the typeface. + @param name the typeface's name + @param ascent the ascent - this is normalised to a height of 1.0 and this is + the value that will be returned by Typeface::getAscent(). The + descent is assumed to be (1.0 - ascent) + @param isBold should be true if the typeface is bold + @param isItalic should be true if the typeface is italic + @param defaultCharacter the character to be used as a replacement if there's + no glyph available for the character that's being drawn */ - const Line withShortenedStart (const float distanceToShortenBy) const throw(); + void setCharacteristics (const String& name, const float ascent, + const bool isBold, const bool isItalic, + const juce_wchar defaultCharacter) throw(); - /** Returns a shortened copy of this line. + /** Adds a glyph to the typeface. - This will chop off part of the end of this line by a certain amount, (leaving the - start-point the same), and return the new line. + The path that is passed in is normalised so that the font height is 1.0, and its + origin is the anchor point of the character on its baseline. + + The width is the nominal width of the character, and any extra kerning values that + are specified will be added to this width. */ - const Line withShortenedEnd (const float distanceToShortenBy) const throw(); + void addGlyph (const juce_wchar character, const Path& path, const float width) throw(); - /** Cuts off parts of this line to keep the parts that are either inside or - outside a path. + /** Specifies an extra kerning amount to be used between a pair of characters. + The amount will be added to the nominal width of the first character when laying out a string. + */ + void addKerningPair (const juce_wchar char1, const juce_wchar char2, const float extraAmount) throw(); - Note that this isn't smart enough to cope with situations where the - line would need to be cut into multiple pieces to correctly clip against - a re-entrant shape. + /** Adds a range of glyphs from another typeface. + This will attempt to pull in the paths and kerning information from another typeface and + add it to this one. + */ + void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) throw(); - @param path the path to clip against - @param keepSectionOutsidePath if true, it's the section outside the path - that will be kept; if false its the section inside - the path - @returns true if the line was changed. + /** Saves this typeface as a Juce-formatted font file. + A CustomTypeface can be created to reload the data that is written - see the CustomTypeface + constructor. */ - bool clipToPath (const Path& path, - const bool keepSectionOutsidePath) throw(); + bool writeToStream (OutputStream& outputStream); + + // The following methods implement the basic Typeface behaviour. + float getAscent() const; + float getDescent() const; + float getStringWidth (const String& text); + void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets); + bool getOutlineForGlyph (int glyphNumber, Path& path); + int getGlyphForCharacter (juce_wchar character); juce_UseDebuggingNewOperator -private: - float startX, startY, endX, endY; -}; +protected: + juce_wchar defaultCharacter; + float ascent; + bool isBold, isItalic; -#endif // __JUCE_LINE_JUCEHEADER__ -/********* End of inlined file: juce_Line.h *********/ + /** If a subclass overrides this, it can load glyphs into the font on-demand. + When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a + particular character and there's no corresponding glyph, they'll call this + method so that a subclass can try to add that glyph, returning true if it + manages to do so. + */ + virtual bool loadGlyphIfPossible (const juce_wchar characterNeeded); -/********* Start of inlined file: juce_Colours.h *********/ -#ifndef __JUCE_COLOURS_JUCEHEADER__ -#define __JUCE_COLOURS_JUCEHEADER__ +private: -/********* Start of inlined file: juce_Colour.h *********/ -#ifndef __JUCE_COLOUR_JUCEHEADER__ -#define __JUCE_COLOUR_JUCEHEADER__ + OwnedArray glyphs; + short lookupTable [128]; -/********* Start of inlined file: juce_PixelFormats.h *********/ -#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ -#define __JUCE_PIXELFORMATS_JUCEHEADER__ + CustomTypeface (const CustomTypeface&); + const CustomTypeface& operator= (const CustomTypeface&); -#if JUCE_MSVC - #pragma pack (push, 1) - #define PACKED -#elif JUCE_GCC - #define PACKED __attribute__((packed)) -#else - #define PACKED -#endif + CustomTypefaceGlyphInfo* findGlyph (const juce_wchar character, const bool loadIfNeeded) throw(); + CustomTypefaceGlyphInfo* findGlyphSubstituting (const juce_wchar character) throw(); +}; -class PixelRGB; -class PixelAlpha; +#endif // __JUCE_TYPEFACE_JUCEHEADER__ +/********* End of inlined file: juce_Typeface.h *********/ + +class LowLevelGraphicsContext; /** - Represents a 32-bit ARGB pixel with premultiplied alpha, and can perform compositing - operations with it. + Represents a particular font, including its size, style, etc. - This is used internally by the imaging classes. + Apart from the typeface to be used, a Font object also dictates whether + the font is bold, italic, underlined, how big it is, and its kerning and + horizontal scale factor. - @see PixelRGB + @see Typeface */ -class JUCE_API PixelARGB +class JUCE_API Font { public: - /** Creates a pixel without defining its colour. */ - PixelARGB() throw() {} - ~PixelARGB() throw() {} - /** Creates a pixel from a 32-bit argb value. + /** A combination of these values is used by the constructor to specify the + style of font to use. */ - PixelARGB (const uint32 argb_) throw() - : argb (argb_) + enum FontStyleFlags { - } + plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */ + bold = 1, /**< boldens the font. @see setStyleFlags */ + italic = 2, /**< finds an italic version of the font. @see setStyleFlags */ + underlined = 4 /**< underlines the font. @see setStyleFlags */ + }; - forcedinline uint32 getARGB() const throw() { return argb; } - forcedinline uint32 getRB() const throw() { return 0x00ff00ff & argb; } - forcedinline uint32 getAG() const throw() { return 0x00ff00ff & (argb >> 8); } + /** Creates a sans-serif font in a given size. - forcedinline uint8 getAlpha() const throw() { return components.a; } - forcedinline uint8 getRed() const throw() { return components.r; } - forcedinline uint8 getGreen() const throw() { return components.g; } - forcedinline uint8 getBlue() const throw() { return components.b; } + @param fontHeight the height in pixels (can be fractional) + @param styleFlags the style to use - this can be a combination of the + Font::bold, Font::italic and Font::underlined, or + just Font::plain for the normal style. + @see FontStyleFlags, getDefaultSansSerifFontName + */ + Font (const float fontHeight, + const int styleFlags = plain) throw(); - /** Blends another pixel onto this one. + /** Creates a font with a given typeface and parameters. - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. + @param typefaceName the name of the typeface to use + @param fontHeight the height in pixels (can be fractional) + @param styleFlags the style to use - this can be a combination of the + Font::bold, Font::italic and Font::underlined, or + just Font::plain for the normal style. + @see FontStyleFlags, getDefaultSansSerifFontName */ - forcedinline void blend (const PixelARGB& src) throw() - { - uint32 sargb = src.getARGB(); - const uint32 alpha = 0x100 - (sargb >> 24); + Font (const String& typefaceName, + const float fontHeight, + const int styleFlags) throw(); - sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); - sargb += 0xff00ff00 & (getAG() * alpha); - - argb = sargb; - } - - /** Blends another pixel onto this one. + /** Creates a copy of another Font object. */ + Font (const Font& other) throw(); - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. - */ - forcedinline void blend (const PixelAlpha& src) throw(); + /** Creates a font for a typeface. */ + Font (const Typeface::Ptr& typeface) throw(); - /** Blends another pixel onto this one. + /** Creates a basic sans-serif font at a default height. - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. + You should use one of the other constructors for creating a font that you're planning + on drawing with - this constructor is here to help initialise objects before changing + the font's settings later. */ - forcedinline void blend (const PixelRGB& src) throw(); + Font() throw(); - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. + /** Copies this font from another one. */ + const Font& operator= (const Font& other) throw(); - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. - */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() - { - ++extraAlpha; + bool operator== (const Font& other) const throw(); + bool operator!= (const Font& other) const throw(); - uint32 sargb = ((extraAlpha * src.getAG()) & 0xff00ff00) - | (((extraAlpha * src.getRB()) >> 8) & 0x00ff00ff); + /** Destructor. */ + ~Font() throw(); - const uint32 alpha = 0x100 - (sargb >> 24); + /** Changes the name of the typeface family. - sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); - sargb += 0xff00ff00 & (getAG() * alpha); + e.g. "Arial", "Courier", etc. - argb = sargb; - } + This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), + or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, + but are generic names that are used to represent the various default fonts. + If you need to know the exact typeface name being used, you can call + Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. + If a suitable font isn't found on the machine, it'll just use a default instead. */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) throw() - { - uint32 drb = getRB(); - drb += (((src.getRB() - drb) * amount) >> 8); - drb &= 0x00ff00ff; + void setTypefaceName (const String& faceName) throw(); - uint32 dag = getAG(); - dag += (((src.getAG() - dag) * amount) >> 8); - dag &= 0x00ff00ff; - dag <<= 8; + /** Returns the name of the typeface family that this font uses. - dag |= drb; - argb = dag; - } + e.g. "Arial", "Courier", etc. - /** Copies another pixel colour over this one. + This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), + or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, + but are generic names that are used to represent the various default fonts. - This doesn't blend it - this colour is simply replaced by the other one. + If you need to know the exact typeface name being used, you can call + Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. */ - template - forcedinline void set (const Pixel& src) throw() - { - argb = src.getARGB(); - } + const String& getTypefaceName() const throw() { return font->typefaceName; } - /** Replaces the colour's alpha value with another one. */ - forcedinline void setAlpha (const uint8 newAlpha) throw() - { - components.a = newAlpha; - } + /** Returns a typeface name that represents the default sans-serif font. - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int multiplier) throw() - { - ++multiplier; + This is also the typeface that will be used when a font is created without + specifying any typeface details. - argb = ((multiplier * getAG()) & 0xff00ff00) - | (((multiplier * getRB()) >> 8) & 0x00ff00ff); - } + Note that this method just returns a generic placeholder string that means "the default + sans-serif font" - it's not the actual name of this font. To get the actual name, use + getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). - forcedinline void multiplyAlpha (const float multiplier) throw() - { - multiplyAlpha ((int) (multiplier * 256.0f)); - } + @see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName + */ + static const String getDefaultSansSerifFontName() throw(); - /** Sets the pixel's colour from individual components. */ - void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) throw() - { - components.b = b; - components.g = g; - components.r = r; - components.a = a; - } + /** Returns a typeface name that represents the default sans-serif font. - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() throw() - { - const uint32 alpha = components.a; + Note that this method just returns a generic placeholder string that means "the default + serif font" - it's not the actual name of this font. To get the actual name, use + getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). - if (alpha < 0xff) - { - if (alpha == 0) - { - components.b = 0; - components.g = 0; - components.r = 0; - } - else - { - components.b = (uint8) ((components.b * alpha + 0x7f) >> 8); - components.g = (uint8) ((components.g * alpha + 0x7f) >> 8); - components.r = (uint8) ((components.r * alpha + 0x7f) >> 8); - } - } - } + @see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName + */ + static const String getDefaultSerifFontName() throw(); - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() throw() - { - const uint32 alpha = components.a; + /** Returns a typeface name that represents the default sans-serif font. - if (alpha < 0xff) - { - if (alpha == 0) - { - components.b = 0; - components.g = 0; - components.r = 0; - } - else - { - components.b = (uint8) jmin (0xff, (components.b * 0xff) / alpha); - components.g = (uint8) jmin (0xff, (components.g * 0xff) / alpha); - components.r = (uint8) jmin (0xff, (components.r * 0xff) / alpha); - } - } - } + Note that this method just returns a generic placeholder string that means "the default + monospaced font" - it's not the actual name of this font. To get the actual name, use + getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). - forcedinline void desaturate() throw() - { - if (components.a < 0xff && components.a > 0) - { - const int newUnpremultipliedLevel = (0xff * ((int) components.r + (int) components.g + (int) components.b) / (3 * components.a)); + @see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName + */ + static const String getDefaultMonospacedFontName() throw(); - components.r = components.g = components.b - = (uint8) ((newUnpremultipliedLevel * components.a + 0x7f) >> 8); - } - else - { - components.r = components.g = components.b - = (uint8) (((int) components.r + (int) components.g + (int) components.b) / 3); - } - } + /** Returns the typeface names of the default fonts on the current platform. */ + static void getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed) throw(); - /** The indexes of the different components in the byte layout of this type of colour. */ - #if JUCE_BIG_ENDIAN - enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 }; - #else - enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 }; - #endif + /** Returns the total height of this font. -private: + This is the maximum height, from the top of the ascent to the bottom of the + descenders. - union - { - uint32 argb; + @see setHeight, setHeightWithoutChangingWidth, getAscent + */ + float getHeight() const throw() { return font->height; } - struct - { -#if JUCE_BIG_ENDIAN - uint8 a : 8, r : 8, g : 8, b : 8; -#else - uint8 b, g, r, a; -#endif - } PACKED components; - }; + /** Changes the font's height. -} PACKED; + @see getHeight, setHeightWithoutChangingWidth + */ + void setHeight (float newHeight) throw(); -/** - Represents a 24-bit RGB pixel, and can perform compositing operations on it. + /** Changes the font's height without changing its width. - This is used internally by the imaging classes. + This alters the horizontal scale to compensate for the change in height. + */ + void setHeightWithoutChangingWidth (float newHeight) throw(); - @see PixelARGB -*/ -class JUCE_API PixelRGB -{ -public: - /** Creates a pixel without defining its colour. */ - PixelRGB() throw() {} - ~PixelRGB() throw() {} + /** Returns the height of the font above its baseline. - /** Creates a pixel from a 32-bit argb value. + This is the maximum height from the baseline to the top. - (The argb format is that used by PixelARGB) + @see getHeight, getDescent */ - PixelRGB (const uint32 argb) throw() - { - r = (uint8) (argb >> 16); - g = (uint8) (argb >> 8); - b = (uint8) (argb); - } - - forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } - forcedinline uint32 getRB() const throw() { return b | (uint32) (r << 16); } - forcedinline uint32 getAG() const throw() { return 0xff0000 | g; } + float getAscent() const throw(); - forcedinline uint8 getAlpha() const throw() { return 0xff; } - forcedinline uint8 getRed() const throw() { return r; } - forcedinline uint8 getGreen() const throw() { return g; } - forcedinline uint8 getBlue() const throw() { return b; } + /** Returns the amount that the font descends below its baseline. - /** Blends another pixel onto this one. + This is calculated as (getHeight() - getAscent()). - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. + @see getAscent, getHeight */ - forcedinline void blend (const PixelARGB& src) throw() - { - uint32 sargb = src.getARGB(); - const uint32 alpha = 0x100 - (sargb >> 24); - - sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); - sargb += 0x0000ff00 & (g * alpha); + float getDescent() const throw(); - r = (uint8) (sargb >> 16); - g = (uint8) (sargb >> 8); - b = (uint8) sargb; - } + /** Returns the font's style flags. - forcedinline void blend (const PixelRGB& src) throw() - { - set (src); - } + This will return a bitwise-or'ed combination of values from the FontStyleFlags + enum, to describe whether the font is bold, italic, etc. - forcedinline void blend (const PixelAlpha& src) throw(); + @see FontStyleFlags + */ + int getStyleFlags() const throw() { return font->styleFlags; } - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. + /** Changes the font's style. - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. + @param newFlags a bitwise-or'ed combination of values from the FontStyleFlags + enum, to set the font's properties + @see FontStyleFlags */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() - { - ++extraAlpha; - const uint32 srb = (extraAlpha * src.getRB()) >> 8; - const uint32 sag = extraAlpha * src.getAG(); - uint32 sargb = (sag & 0xff00ff00) | (srb & 0x00ff00ff); + void setStyleFlags (const int newFlags) throw(); - const uint32 alpha = 0x100 - (sargb >> 24); + /** Makes the font bold or non-bold. */ + void setBold (const bool shouldBeBold) throw(); + /** Returns true if the font is bold. */ + bool isBold() const throw(); - sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); - sargb += 0x0000ff00 & (g * alpha); + /** Makes the font italic or non-italic. */ + void setItalic (const bool shouldBeItalic) throw(); + /** Returns true if the font is italic. */ + bool isItalic() const throw(); - b = (uint8) sargb; - g = (uint8) (sargb >> 8); - r = (uint8) (sargb >> 16); - } + /** Makes the font underlined or non-underlined. */ + void setUnderline (const bool shouldBeUnderlined) throw(); + /** Returns true if the font is underlined. */ + bool isUnderlined() const throw(); - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. - */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) throw() - { - uint32 drb = getRB(); - drb += (((src.getRB() - drb) * amount) >> 8); + /** Changes the font's horizontal scale factor. - uint32 dag = getAG(); - dag += (((src.getAG() - dag) * amount) >> 8); + @param scaleFactor a value of 1.0 is the normal scale, less than this will be + narrower, greater than 1.0 will be stretched out. + */ + void setHorizontalScale (const float scaleFactor) throw(); - b = (uint8) drb; - g = (uint8) dag; - r = (uint8) (drb >> 16); - } + /** Returns the font's horizontal scale. - /** Copies another pixel colour over this one. + A value of 1.0 is the normal scale, less than this will be narrower, greater + than 1.0 will be stretched out. - This doesn't blend it - this colour is simply replaced by the other one. - Because PixelRGB has no alpha channel, any alpha value in the source pixel - is thrown away. + @see setHorizontalScale */ - template - forcedinline void set (const Pixel& src) throw() - { - b = src.getBlue(); - g = src.getGreen(); - r = src.getRed(); - } + float getHorizontalScale() const throw() { return font->horizontalScale; } - /** This method is included for compatibility with the PixelARGB class. */ - forcedinline void setAlpha (const uint8) throw() {} + /** Changes the font's kerning. - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int) throw() {} + @param extraKerning a multiple of the font's height that will be added + to space between the characters. So a value of zero is + normal spacing, positive values spread the letters out, + negative values make them closer together. + */ + void setExtraKerningFactor (const float extraKerning) throw(); - /** Sets the pixel's colour from individual components. */ - void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) throw() - { - r = r_; - g = g_; - b = b_; - } + /** Returns the font's kerning. - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() throw() {} + This is the extra space added between adjacent characters, as a proportion + of the font's height. - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() throw() {} + A value of zero is normal spacing, positive values will spread the letters + out more, and negative values make them closer together. + */ + float getExtraKerningFactor() const throw() { return font->kerning; } - forcedinline void desaturate() throw() - { - r = g = b = (uint8) (((int) r + (int) g + (int) b) / 3); - } + /** Changes all the font's characteristics with one call. */ + void setSizeAndStyle (float newHeight, + const int newStyleFlags, + const float newHorizontalScale, + const float newKerningAmount) throw(); - /** The indexes of the different components in the byte layout of this type of colour. */ - #if JUCE_MAC - enum { indexR = 0, indexG = 1, indexB = 2 }; - #else - enum { indexR = 2, indexG = 1, indexB = 0 }; - #endif + /** Returns the total width of a string as it would be drawn using this font. -private: + For a more accurate floating-point result, use getStringWidthFloat(). + */ + int getStringWidth (const String& text) const throw(); -#if JUCE_MAC - uint8 r, g, b; -#else - uint8 b, g, r; -#endif + /** Returns the total width of a string as it would be drawn using this font. -} PACKED; + @see getStringWidth + */ + float getStringWidthFloat (const String& text) const throw(); -forcedinline void PixelARGB::blend (const PixelRGB& src) throw() -{ - set (src); -} + /** Returns the series of glyph numbers and their x offsets needed to represent a string. -/** - Represents an 8-bit single-channel pixel, and can perform compositing operations on it. + An extra x offset is added at the end of the run, to indicate where the right hand + edge of the last character is. + */ + void getGlyphPositions (const String& text, Array & glyphs, Array & xOffsets) const throw(); - This is used internally by the imaging classes. + /** Returns the typeface used by this font. - @see PixelARGB, PixelRGB -*/ -class JUCE_API PixelAlpha -{ -public: - /** Creates a pixel without defining its colour. */ - PixelAlpha() throw() {} - ~PixelAlpha() throw() {} + Note that the object returned may go out of scope if this font is deleted + or has its style changed. + */ + Typeface* getTypeface() const throw(); - /** Creates a pixel from a 32-bit argb value. + /** Creates an array of Font objects to represent all the fonts on the system. - (The argb format is that used by PixelARGB) - */ - PixelAlpha (const uint32 argb) throw() - { - a = (uint8) (argb >> 24); - } + If you just need the names of the typefaces, you can also use + findAllTypefaceNames() instead. - forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } - forcedinline uint32 getRB() const throw() { return (((uint32) a) << 16) | a; } - forcedinline uint32 getAG() const throw() { return (((uint32) a) << 16) | a; } + @param results the array to which new Font objects will be added. + */ + static void findFonts (OwnedArray& results) throw(); - forcedinline uint8 getAlpha() const throw() { return a; } - forcedinline uint8 getRed() const throw() { return 0; } - forcedinline uint8 getGreen() const throw() { return 0; } - forcedinline uint8 getBlue() const throw() { return 0; } + /** Returns a list of all the available typeface names. - /** Blends another pixel onto this one. + The names returned can be passed into setTypefaceName(). - This takes into account the opacity of the pixel being overlaid, and blends - it accordingly. + You can use this instead of findFonts() if you only need their names, and not + font objects. */ - template - forcedinline void blend (const Pixel& src) throw() - { - const int srcA = src.getAlpha(); - a = (uint8) ((a * (0x100 - srcA) >> 8) + srcA); - } - - /** Blends another pixel onto this one, applying an extra multiplier to its opacity. + static const StringArray findAllTypefaceNames() throw(); - The opacity of the pixel being overlaid is scaled by the extraAlpha factor before - being used, so this can blend semi-transparently from a PixelRGB argument. + /** Returns the name of the typeface to be used for rendering glyphs that aren't found + in the requested typeface. */ - template - forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() - { - ++extraAlpha; - const int srcAlpha = (extraAlpha * src.getAlpha()) >> 8; - a = (uint8) ((a * (0x100 - srcAlpha) >> 8) + srcAlpha); - } + static const String getFallbackFontName() throw(); - /** Blends another pixel with this one, creating a colour that is somewhere - between the two, as specified by the amount. + /** Sets the (platform-specific) name of the typeface to use to find glyphs that aren't + available in whatever font you're trying to use. */ - template - forcedinline void tween (const Pixel& src, const uint32 amount) throw() - { - a += ((src,getAlpha() - a) * amount) >> 8; - } + static void setFallbackFontName (const String& name) throw(); - /** Copies another pixel colour over this one. + juce_UseDebuggingNewOperator - This doesn't blend it - this colour is simply replaced by the other one. - */ - template - forcedinline void set (const Pixel& src) throw() - { - a = src.getAlpha(); - } +private: - /** Replaces the colour's alpha value with another one. */ - forcedinline void setAlpha (const uint8 newAlpha) throw() - { - a = newAlpha; - } + friend class FontGlyphAlphaMap; + friend class TypefaceCache; - /** Multiplies the colour's alpha value with another one. */ - forcedinline void multiplyAlpha (int multiplier) throw() + class SharedFontInternal : public ReferenceCountedObject { - ++multiplier; - a = (uint8) ((a * multiplier) >> 8); - } + public: + SharedFontInternal (const String& typefaceName, const float height, const float horizontalScale, + const float kerning, const float ascent, const int styleFlags, + Typeface* const typeface) throw(); + SharedFontInternal (const SharedFontInternal& other) throw(); - forcedinline void multiplyAlpha (const float multiplier) throw() - { - a = (uint8) (a * multiplier); - } + String typefaceName; + float height, horizontalScale, kerning, ascent; + int styleFlags; + Typeface::Ptr typeface; + }; - /** Sets the pixel's colour from individual components. */ - forcedinline void setARGB (const uint8 a_, const uint8 r, const uint8 g, const uint8 b) throw() - { - a = a_; - } + ReferenceCountedObjectPtr font; + void dupeInternalIfShared() throw(); +}; - /** Premultiplies the pixel's RGB values by its alpha. */ - forcedinline void premultiply() throw() - { - } +#endif // __JUCE_FONT_JUCEHEADER__ +/********* End of inlined file: juce_Font.h *********/ - /** Unpremultiplies the pixel's RGB values. */ - forcedinline void unpremultiply() throw() - { - } +/********* Start of inlined file: juce_PathStrokeType.h *********/ +#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ +#define __JUCE_PATHSTROKETYPE_JUCEHEADER__ - forcedinline void desaturate() throw() +/** + Describes a type of stroke used to render a solid outline along a path. + + A PathStrokeType object can be used directly to create the shape of an outline + around a path, and is used by Graphics::strokePath to specify the type of + stroke to draw. + + @see Path, Graphics::strokePath +*/ +class JUCE_API PathStrokeType +{ +public: + + /** The type of shape to use for the corners between two adjacent line segments. */ + enum JointStyle { - } + mitered, /**< Indicates that corners should be drawn with sharp joints. + Note that for angles that curve back on themselves, drawing a + mitre could require extending the point too far away from the + path, so a mitre limit is imposed and any corners that exceed it + are drawn as bevelled instead. */ + curved, /**< Indicates that corners should be drawn as rounded-off. */ + beveled /**< Indicates that corners should be drawn with a line flattening their + outside edge. */ + }; -private: + /** The type shape to use for the ends of lines. */ + enum EndCapStyle + { + butt, /**< Ends of lines are flat and don't extend beyond the end point. */ + square, /**< Ends of lines are flat, but stick out beyond the end point for half + the thickness of the stroke. */ + rounded /**< Ends of lines are rounded-off with a circular shape. */ + }; - uint8 a : 8; -} PACKED; + /** Creates a stroke type. -forcedinline void PixelRGB::blend (const PixelAlpha& src) throw() -{ - blend (PixelARGB (src.getARGB())); -} + @param strokeThickness the width of the line to use + @param jointStyle the type of joints to use for corners + @param endStyle the type of end-caps to use for the ends of open paths. + */ + PathStrokeType (const float strokeThickness, + const JointStyle jointStyle = mitered, + const EndCapStyle endStyle = butt) throw(); -forcedinline void PixelARGB::blend (const PixelAlpha& src) throw() -{ - uint32 sargb = src.getARGB(); - const uint32 alpha = 0x100 - (sargb >> 24); + /** Createes a copy of another stroke type. */ + PathStrokeType (const PathStrokeType& other) throw(); - sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); - sargb += 0xff00ff00 & (getAG() * alpha); + /** Copies another stroke onto this one. */ + const PathStrokeType& operator= (const PathStrokeType& other) throw(); - argb = sargb; -} + /** Destructor. */ + ~PathStrokeType() throw(); -#if JUCE_MSVC - #pragma pack (pop) -#endif + /** Applies this stroke type to a path and returns the resultant stroke as another Path. -#undef PACKED + @param destPath the resultant stroked outline shape will be copied into this path. + Note that it's ok for the source and destination Paths to be + the same object, so you can easily turn a path into a stroked version + of itself. + @param sourcePath the path to use as the source + @param transform an optional transform to apply to the points from the source path + as they are being used + @param extraAccuracy if this is greater than 1.0, it will subdivide the path to + a higher resolution, which improved the quality if you'll later want + to enlarge the stroked path -#endif // __JUCE_PIXELFORMATS_JUCEHEADER__ -/********* End of inlined file: juce_PixelFormats.h *********/ + @see createDashedStroke + */ + void createStrokedPath (Path& destPath, + const Path& sourcePath, + const AffineTransform& transform = AffineTransform::identity, + const float extraAccuracy = 1.0f) const throw(); -/** - Represents a colour, also including a transparency value. + /** Applies this stroke type to a path, creating a dashed line. - The colour is stored internally as unsigned 8-bit red, green, blue and alpha values. -*/ -class JUCE_API Colour -{ -public: + This is similar to createStrokedPath, but uses the array passed in to + break the stroke up into a series of dashes. - /** Creates a transparent black colour. */ - Colour() throw(); + @param destPath the resultant stroked outline shape will be copied into this path. + Note that it's ok for the source and destination Paths to be + the same object, so you can easily turn a path into a stroked version + of itself. + @param sourcePath the path to use as the source + @param dashLengths An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create + a line of length 2, then skip a length of 3, then add a line of length 4, + skip 5, and keep repeating this pattern. + @param numDashLengths The number of lengths in the dashLengths array. This should really be + an even number, otherwise the pattern will get out of step as it + repeats. + @param transform an optional transform to apply to the points from the source path + as they are being used + @param extraAccuracy if this is greater than 1.0, it will subdivide the path to + a higher resolution, which improved the quality if you'll later want + to enlarge the stroked path + */ + void createDashedStroke (Path& destPath, + const Path& sourcePath, + const float* dashLengths, + int numDashLengths, + const AffineTransform& transform = AffineTransform::identity, + const float extraAccuracy = 1.0f) const throw(); - /** Creates a copy of another Colour object. */ - Colour (const Colour& other) throw(); + /** Returns the stroke thickness. */ + float getStrokeThickness() const throw() { return thickness; } - /** Creates a colour from a 32-bit ARGB value. + /** Returns the joint style. */ + JointStyle getJointStyle() const throw() { return jointStyle; } - The format of this number is: - ((alpha << 24) | (red << 16) | (green << 8) | blue). + /** Returns the end-cap style. */ + EndCapStyle getEndStyle() const throw() { return endStyle; } - All components in the range 0x00 to 0xff. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. + juce_UseDebuggingNewOperator - @see getPixelARGB - */ - explicit Colour (const uint32 argb) throw(); + /** Compares the stroke thickness, joint and end styles of two stroke types. */ + bool operator== (const PathStrokeType& other) const throw(); - /** Creates an opaque colour using 8-bit red, green and blue values */ - Colour (const uint8 red, - const uint8 green, - const uint8 blue) throw(); + /** Compares the stroke thickness, joint and end styles of two stroke types. */ + bool operator!= (const PathStrokeType& other) const throw(); - /** Creates an opaque colour using 8-bit red, green and blue values */ - static const Colour fromRGB (const uint8 red, - const uint8 green, - const uint8 blue) throw(); +private: - /** Creates a colour using 8-bit red, green, blue and alpha values. */ - Colour (const uint8 red, - const uint8 green, - const uint8 blue, - const uint8 alpha) throw(); + float thickness; + JointStyle jointStyle; + EndCapStyle endStyle; +}; - /** Creates a colour using 8-bit red, green, blue and alpha values. */ - static const Colour fromRGBA (const uint8 red, - const uint8 green, - const uint8 blue, - const uint8 alpha) throw(); +#endif // __JUCE_PATHSTROKETYPE_JUCEHEADER__ +/********* End of inlined file: juce_PathStrokeType.h *********/ - /** Creates a colour from 8-bit red, green, and blue values, and a floating-point alpha. +/********* Start of inlined file: juce_Line.h *********/ +#ifndef __JUCE_LINE_JUCEHEADER__ +#define __JUCE_LINE_JUCEHEADER__ - Alpha of 0.0 is transparent, alpha of 1.0f is opaque. - Values outside the valid range will be clipped. - */ - Colour (const uint8 red, - const uint8 green, - const uint8 blue, - const float alpha) throw(); +/** + Represents a line, using 32-bit float co-ordinates. - /** Creates a colour using 8-bit red, green, blue and float alpha values. */ - static const Colour fromRGBAFloat (const uint8 red, - const uint8 green, - const uint8 blue, - const float alpha) throw(); + This class contains a bunch of useful methods for various geometric + tasks. - /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. + @see Point, Rectangle, Path, Graphics::drawLine +*/ +class JUCE_API Line +{ +public: - The floating point values must be between 0.0 and 1.0. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - Values outside the valid range will be clipped. - */ - Colour (const float hue, - const float saturation, - const float brightness, - const uint8 alpha) throw(); + /** Creates a line, using (0, 0) as its start and end points. */ + Line() throw(); - /** Creates a colour using floating point hue, saturation, brightness and alpha values. + /** Creates a copy of another line. */ + Line (const Line& other) throw(); - All values must be between 0.0 and 1.0. - Numbers outside the valid range will be clipped. - */ - Colour (const float hue, - const float saturation, - const float brightness, - const float alpha) throw(); + /** Creates a line based on the co-ordinates of its start and end points. */ + Line (const float startX, + const float startY, + const float endX, + const float endY) throw(); - /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. + /** Creates a line from its start and end points. */ + Line (const Point& start, + const Point& end) throw(); - The floating point values must be between 0.0 and 1.0. - An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - Values outside the valid range will be clipped. - */ - static const Colour fromHSV (const float hue, - const float saturation, - const float brightness, - const float alpha) throw(); + /** Copies a line from another one. */ + const Line& operator= (const Line& other) throw(); /** Destructor. */ - ~Colour() throw(); + ~Line() throw(); - /** Copies another Colour object. */ - const Colour& operator= (const Colour& other) throw(); + /** Returns the x co-ordinate of the line's start point. */ + inline float getStartX() const throw() { return startX; } - /** Compares two colours. */ - bool operator== (const Colour& other) const throw(); - /** Compares two colours. */ - bool operator!= (const Colour& other) const throw(); + /** Returns the y co-ordinate of the line's start point. */ + inline float getStartY() const throw() { return startY; } - /** Returns the red component of this colour. + /** Returns the x co-ordinate of the line's end point. */ + inline float getEndX() const throw() { return endX; } - @returns a value between 0x00 and 0xff. - */ - uint8 getRed() const throw() { return argb.getRed(); } + /** Returns the y co-ordinate of the line's end point. */ + inline float getEndY() const throw() { return endY; } - /** Returns the green component of this colour. + /** Returns the line's start point. */ + const Point getStart() const throw(); - @returns a value between 0x00 and 0xff. - */ - uint8 getGreen() const throw() { return argb.getGreen(); } + /** Returns the line's end point. */ + const Point getEnd() const throw(); - /** Returns the blue component of this colour. + /** Changes this line's start point */ + void setStart (const float newStartX, + const float newStartY) throw(); - @returns a value between 0x00 and 0xff. - */ - uint8 getBlue() const throw() { return argb.getBlue(); } + /** Changes this line's end point */ + void setEnd (const float newEndX, + const float newEndY) throw(); - /** Returns the red component of this colour as a floating point value. + /** Changes this line's start point */ + void setStart (const Point& newStart) throw(); - @returns a value between 0.0 and 1.0 - */ - float getFloatRed() const throw(); + /** Changes this line's end point */ + void setEnd (const Point& newEnd) throw(); - /** Returns the green component of this colour as a floating point value. + /** Applies an affine transform to the line's start and end points. */ + void applyTransform (const AffineTransform& transform) throw(); - @returns a value between 0.0 and 1.0 - */ - float getFloatGreen() const throw(); + /** Returns the length of the line. */ + float getLength() const throw(); - /** Returns the blue component of this colour as a floating point value. + /** Returns true if the line's start and end x co-ordinates are the same. */ + bool isVertical() const throw(); - @returns a value between 0.0 and 1.0 - */ - float getFloatBlue() const throw(); + /** Returns true if the line's start and end y co-ordinates are the same. */ + bool isHorizontal() const throw(); - /** Returns a premultiplied ARGB pixel object that represents this colour. + /** Returns the line's angle. + + This value is the number of radians clockwise from the 3 o'clock direction, + where the line's start point is considered to be at the centre. */ - const PixelARGB getPixelARGB() const throw(); + float getAngle() const throw(); - /** Returns a 32-bit integer that represents this colour. + /** Compares two lines. */ + bool operator== (const Line& other) const throw(); - The format of this number is: - ((alpha << 24) | (red << 16) | (green << 16) | blue). - */ - uint32 getARGB() const throw(); + /** Compares two lines. */ + bool operator!= (const Line& other) const throw(); - /** Returns the colour's alpha (opacity). + /** Finds the intersection between two lines. - Alpha of 0x00 is completely transparent, 0xff is completely opaque. + @param line the other line + @param intersectionX the x co-ordinate of the point where the lines meet (or + where they would meet if they were infinitely long) + the intersection (if the lines intersect). If the lines + are parallel, this will just be set to the position + of one of the line's endpoints. + @param intersectionY the y co-ordinate of the point where the lines meet + @returns true if the line segments intersect; false if they dont. Even if they + don't intersect, the intersection co-ordinates returned will still + be valid */ - uint8 getAlpha() const throw() { return argb.getAlpha(); } + bool intersects (const Line& line, + float& intersectionX, + float& intersectionY) const throw(); - /** Returns the colour's alpha (opacity) as a floating point value. + /** Returns the location of the point which is a given distance along this line. - Alpha of 0.0 is completely transparent, 1.0 is completely opaque. + @param distanceFromStart the distance to move along the line from its + start point. This value can be negative or longer + than the line itself + @see getPointAlongLineProportionally */ - float getFloatAlpha() const throw(); + const Point getPointAlongLine (const float distanceFromStart) const throw(); - /** Returns true if this colour is completely opaque. + /** Returns a point which is a certain distance along and to the side of this line. - Equivalent to (getAlpha() == 0xff). + This effectively moves a given distance along the line, then another distance + perpendicularly to this, and returns the resulting position. + + @param distanceFromStart the distance to move along the line from its + start point. This value can be negative or longer + than the line itself + @param perpendicularDistance how far to move sideways from the line. If you're + looking along the line from its start towards its + end, then a positive value here will move to the + right, negative value move to the left. */ - bool isOpaque() const throw(); + const Point getPointAlongLine (const float distanceFromStart, + const float perpendicularDistance) const throw(); - /** Returns true if this colour is completely transparent. + /** Returns the location of the point which is a given distance along this line + proportional to the line's length. - Equivalent to (getAlpha() == 0x00). + @param proportionOfLength the distance to move along the line from its + start point, in multiples of the line's length. + So a value of 0.0 will return the line's start point + and a value of 1.0 will return its end point. (This value + can be negative or greater than 1.0). + @see getPointAlongLine */ - bool isTransparent() const throw(); - - /** Returns a colour that's the same colour as this one, but with a new alpha value. */ - const Colour withAlpha (const uint8 newAlpha) const throw(); + const Point getPointAlongLineProportionally (const float proportionOfLength) const throw(); - /** Returns a colour that's the same colour as this one, but with a new alpha value. */ - const Colour withAlpha (const float newAlpha) const throw(); + /** Returns the smallest distance between this line segment and a given point. - /** Returns a colour that's the same colour as this one, but with a modified alpha value. + So if the point is close to the line, this will return the perpendicular + distance from the line; if the point is a long way beyond one of the line's + end-point's, it'll return the straight-line distance to the nearest end-point. - The new colour's alpha will be this object's alpha multiplied by the value passed-in. + @param x x position of the point to test + @param y y position of the point to test + @returns the point's distance from the line + @see getPositionAlongLineOfNearestPoint */ - const Colour withMultipliedAlpha (const float alphaMultiplier) const throw(); + float getDistanceFromLine (const float x, + const float y) const throw(); - /** Returns a colour that is the result of alpha-compositing a new colour over this one. + /** Finds the point on this line which is nearest to a given point, and + returns its position as a proportional position along the line. - If the foreground colour is semi-transparent, it is blended onto this colour - accordingly. + @param x x position of the point to test + @param y y position of the point to test + @returns a value 0 to 1.0 which is the distance along this line from the + line's start to the point which is nearest to the point passed-in. To + turn this number into a position, use getPointAlongLineProportionally(). + @see getDistanceFromLine, getPointAlongLineProportionally */ - const Colour overlaidWith (const Colour& foregroundColour) const throw(); + float findNearestPointTo (const float x, + const float y) const throw(); - /** Returns a colour that lies somewhere between this one and another. + /** Returns true if the given point lies above this line. - If amountOfOther is zero, the result is 100% this colour, if amountOfOther - is 1.0, the result is 100% of the other colour. + The return value is true if the point's y coordinate is less than the y + coordinate of this line at the given x (assuming the line extends infinitely + in both directions). */ - const Colour interpolatedWith (const Colour& other, float proportionOfOther) const throw(); + bool isPointAbove (const float x, const float y) const throw(); - /** Returns the colour's hue component. - The value returned is in the range 0.0 to 1.0 - */ - float getHue() const throw(); + /** Returns a shortened copy of this line. - /** Returns the colour's saturation component. - The value returned is in the range 0.0 to 1.0 + This will chop off part of the start of this line by a certain amount, (leaving the + end-point the same), and return the new line. */ - float getSaturation() const throw(); + const Line withShortenedStart (const float distanceToShortenBy) const throw(); - /** Returns the colour's brightness component. - The value returned is in the range 0.0 to 1.0 - */ - float getBrightness() const throw(); + /** Returns a shortened copy of this line. - /** Returns the colour's hue, saturation and brightness components all at once. - The values returned are in the range 0.0 to 1.0 + This will chop off part of the end of this line by a certain amount, (leaving the + start-point the same), and return the new line. */ - void getHSB (float& hue, - float& saturation, - float& brightness) const throw(); + const Line withShortenedEnd (const float distanceToShortenBy) const throw(); - /** Returns a copy of this colour with a different hue. */ - const Colour withHue (const float newHue) const throw(); + /** Cuts off parts of this line to keep the parts that are either inside or + outside a path. - /** Returns a copy of this colour with a different saturation. */ - const Colour withSaturation (const float newSaturation) const throw(); + Note that this isn't smart enough to cope with situations where the + line would need to be cut into multiple pieces to correctly clip against + a re-entrant shape. - /** Returns a copy of this colour with a different brightness. - @see brighter, darker, withMultipliedBrightness + @param path the path to clip against + @param keepSectionOutsidePath if true, it's the section outside the path + that will be kept; if false its the section inside + the path + @returns true if the line was changed. */ - const Colour withBrightness (const float newBrightness) const throw(); + bool clipToPath (const Path& path, + const bool keepSectionOutsidePath) throw(); - /** Returns a copy of this colour with it hue rotated. + juce_UseDebuggingNewOperator - The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) +private: + float startX, startY, endX, endY; +}; - @see brighter, darker, withMultipliedBrightness - */ - const Colour withRotatedHue (const float amountToRotate) const throw(); +#endif // __JUCE_LINE_JUCEHEADER__ +/********* End of inlined file: juce_Line.h *********/ - /** Returns a copy of this colour with its saturation multiplied by the given value. +/********* Start of inlined file: juce_Colours.h *********/ +#ifndef __JUCE_COLOURS_JUCEHEADER__ +#define __JUCE_COLOURS_JUCEHEADER__ - The new colour's saturation is (this->getSaturation() * multiplier) - (the result is clipped to legal limits). - */ - const Colour withMultipliedSaturation (const float multiplier) const throw(); +/********* Start of inlined file: juce_Colour.h *********/ +#ifndef __JUCE_COLOUR_JUCEHEADER__ +#define __JUCE_COLOUR_JUCEHEADER__ - /** Returns a copy of this colour with its brightness multiplied by the given value. +/********* Start of inlined file: juce_PixelFormats.h *********/ +#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ +#define __JUCE_PIXELFORMATS_JUCEHEADER__ - The new colour's saturation is (this->getBrightness() * multiplier) - (the result is clipped to legal limits). - */ - const Colour withMultipliedBrightness (const float amount) const throw(); +#if JUCE_MSVC + #pragma pack (push, 1) + #define PACKED +#elif JUCE_GCC + #define PACKED __attribute__((packed)) +#else + #define PACKED +#endif - /** Returns a brighter version of this colour. +class PixelRGB; +class PixelAlpha; - @param amountBrighter how much brighter to make it - a value from 0 to 1.0 where 0 is - unchanged, and higher values make it brighter - @see withMultipliedBrightness - */ - const Colour brighter (float amountBrighter = 0.4f) const throw(); +/** + Represents a 32-bit ARGB pixel with premultiplied alpha, and can perform compositing + operations with it. - /** Returns a darker version of this colour. + This is used internally by the imaging classes. - @param amountDarker how much darker to make it - a value from 0 to 1.0 where 0 is - unchanged, and higher values make it darker - @see withMultipliedBrightness + @see PixelRGB +*/ +class JUCE_API PixelARGB +{ +public: + /** Creates a pixel without defining its colour. */ + PixelARGB() throw() {} + ~PixelARGB() throw() {} + + /** Creates a pixel from a 32-bit argb value. */ - const Colour darker (float amountDarker = 0.4f) const throw(); + PixelARGB (const uint32 argb_) throw() + : argb (argb_) + { + } - /** Returns a colour that will be clearly visible against this colour. + forcedinline uint32 getARGB() const throw() { return argb; } + forcedinline uint32 getRB() const throw() { return 0x00ff00ff & argb; } + forcedinline uint32 getAG() const throw() { return 0x00ff00ff & (argb >> 8); } - The amount parameter indicates how contrasting the new colour should - be, so e.g. Colours::black.contrasting (0.1f) will return a colour - that's just a little bit lighter; Colours::black.contrasting (1.0f) will - return white; Colours::white.contrasting (1.0f) will return black, etc. + forcedinline uint8 getAlpha() const throw() { return components.a; } + forcedinline uint8 getRed() const throw() { return components.r; } + forcedinline uint8 getGreen() const throw() { return components.g; } + forcedinline uint8 getBlue() const throw() { return components.b; } + + /** Blends another pixel onto this one. + + This takes into account the opacity of the pixel being overlaid, and blends + it accordingly. */ - const Colour contrasting (const float amount = 1.0f) const throw(); + forcedinline void blend (const PixelARGB& src) throw() + { + uint32 sargb = src.getARGB(); + const uint32 alpha = 0x100 - (sargb >> 24); - /** Returns a colour that contrasts against two colours. + sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); + sargb += 0xff00ff00 & (getAG() * alpha); - Looks for a colour that contrasts with both of the colours passed-in. + argb = sargb; + } - Handy for things like choosing a highlight colour in text editors, etc. + /** Blends another pixel onto this one. + + This takes into account the opacity of the pixel being overlaid, and blends + it accordingly. */ - static const Colour contrasting (const Colour& colour1, - const Colour& colour2) throw(); + forcedinline void blend (const PixelAlpha& src) throw(); - /** Returns an opaque shade of grey. + /** Blends another pixel onto this one. - @param brightness the level of grey to return - 0 is black, 1.0 is white + This takes into account the opacity of the pixel being overlaid, and blends + it accordingly. */ - static const Colour greyLevel (const float brightness) throw(); + forcedinline void blend (const PixelRGB& src) throw(); - /** Returns a stringified version of this colour. + /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - The string can be turned back into a colour using the fromString() method. + The opacity of the pixel being overlaid is scaled by the extraAlpha factor before + being used, so this can blend semi-transparently from a PixelRGB argument. */ - const String toString() const throw(); + template + forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() + { + ++extraAlpha; - /** Reads the colour from a string that was created with toString(). + uint32 sargb = ((extraAlpha * src.getAG()) & 0xff00ff00) + | (((extraAlpha * src.getRB()) >> 8) & 0x00ff00ff); + + const uint32 alpha = 0x100 - (sargb >> 24); + + sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); + sargb += 0xff00ff00 & (getAG() * alpha); + + argb = sargb; + } + + /** Blends another pixel with this one, creating a colour that is somewhere + between the two, as specified by the amount. */ - static const Colour fromString (const String& encodedColourString); + template + forcedinline void tween (const Pixel& src, const uint32 amount) throw() + { + uint32 drb = getRB(); + drb += (((src.getRB() - drb) * amount) >> 8); + drb &= 0x00ff00ff; - juce_UseDebuggingNewOperator + uint32 dag = getAG(); + dag += (((src.getAG() - dag) * amount) >> 8); + dag &= 0x00ff00ff; + dag <<= 8; -private: - PixelARGB argb; -}; + dag |= drb; + argb = dag; + } -#endif // __JUCE_COLOUR_JUCEHEADER__ -/********* End of inlined file: juce_Colour.h *********/ + /** Copies another pixel colour over this one. -/** - Contains a set of predefined named colours (mostly standard HTML colours) + This doesn't blend it - this colour is simply replaced by the other one. + */ + template + forcedinline void set (const Pixel& src) throw() + { + argb = src.getARGB(); + } - @see Colour, Colours::greyLevel -*/ -class Colours -{ -public: - static JUCE_API const Colour + /** Replaces the colour's alpha value with another one. */ + forcedinline void setAlpha (const uint8 newAlpha) throw() + { + components.a = newAlpha; + } - transparentBlack, /**< ARGB = 0x00000000 */ - transparentWhite, /**< ARGB = 0x00ffffff */ + /** Multiplies the colour's alpha value with another one. */ + forcedinline void multiplyAlpha (int multiplier) throw() + { + ++multiplier; - black, /**< ARGB = 0xff000000 */ - white, /**< ARGB = 0xffffffff */ - blue, /**< ARGB = 0xff0000ff */ - grey, /**< ARGB = 0xff808080 */ - green, /**< ARGB = 0xff008000 */ - red, /**< ARGB = 0xffff0000 */ - yellow, /**< ARGB = 0xffffff00 */ + argb = ((multiplier * getAG()) & 0xff00ff00) + | (((multiplier * getRB()) >> 8) & 0x00ff00ff); + } - aliceblue, antiquewhite, aqua, aquamarine, - azure, beige, bisque, blanchedalmond, - blueviolet, brown, burlywood, cadetblue, - chartreuse, chocolate, coral, cornflowerblue, - cornsilk, crimson, cyan, darkblue, - darkcyan, darkgoldenrod, darkgrey, darkgreen, - darkkhaki, darkmagenta, darkolivegreen, darkorange, - darkorchid, darkred, darksalmon, darkseagreen, - darkslateblue, darkslategrey, darkturquoise, darkviolet, - deeppink, deepskyblue, dimgrey, dodgerblue, - firebrick, floralwhite, forestgreen, fuchsia, - gainsboro, gold, goldenrod, greenyellow, - honeydew, hotpink, indianred, indigo, - ivory, khaki, lavender, lavenderblush, - lemonchiffon, lightblue, lightcoral, lightcyan, - lightgoldenrodyellow, lightgreen, lightgrey, lightpink, - lightsalmon, lightseagreen, lightskyblue, lightslategrey, - lightsteelblue, lightyellow, lime, limegreen, - linen, magenta, maroon, mediumaquamarine, - mediumblue, mediumorchid, mediumpurple, mediumseagreen, - mediumslateblue, mediumspringgreen, mediumturquoise, mediumvioletred, - midnightblue, mintcream, mistyrose, navajowhite, - navy, oldlace, olive, olivedrab, - orange, orangered, orchid, palegoldenrod, - palegreen, paleturquoise, palevioletred, papayawhip, - peachpuff, peru, pink, plum, - powderblue, purple, rosybrown, royalblue, - saddlebrown, salmon, sandybrown, seagreen, - seashell, sienna, silver, skyblue, - slateblue, slategrey, snow, springgreen, - steelblue, tan, teal, thistle, - tomato, turquoise, violet, wheat, - whitesmoke, yellowgreen; + forcedinline void multiplyAlpha (const float multiplier) throw() + { + multiplyAlpha ((int) (multiplier * 256.0f)); + } - /** Attempts to look up a string in the list of known colour names, and return - the appropriate colour. + /** Sets the pixel's colour from individual components. */ + void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) throw() + { + components.b = b; + components.g = g; + components.r = r; + components.a = a; + } - A non-case-sensitive search is made of the list of predefined colours, and - if a match is found, that colour is returned. If no match is found, the - colour passed in as the defaultColour parameter is returned. - */ - static JUCE_API const Colour findColourForName (const String& colourName, - const Colour& defaultColour); + /** Premultiplies the pixel's RGB values by its alpha. */ + forcedinline void premultiply() throw() + { + const uint32 alpha = components.a; -private: + if (alpha < 0xff) + { + if (alpha == 0) + { + components.b = 0; + components.g = 0; + components.r = 0; + } + else + { + components.b = (uint8) ((components.b * alpha + 0x7f) >> 8); + components.g = (uint8) ((components.g * alpha + 0x7f) >> 8); + components.r = (uint8) ((components.r * alpha + 0x7f) >> 8); + } + } + } - // this isn't a class you should ever instantiate - it's just here for the - // static values in it. - Colours(); -}; + /** Unpremultiplies the pixel's RGB values. */ + forcedinline void unpremultiply() throw() + { + const uint32 alpha = components.a; -#endif // __JUCE_COLOURS_JUCEHEADER__ -/********* End of inlined file: juce_Colours.h *********/ + if (alpha < 0xff) + { + if (alpha == 0) + { + components.b = 0; + components.g = 0; + components.r = 0; + } + else + { + components.b = (uint8) jmin (0xff, (components.b * 0xff) / alpha); + components.g = (uint8) jmin (0xff, (components.g * 0xff) / alpha); + components.r = (uint8) jmin (0xff, (components.r * 0xff) / alpha); + } + } + } -/********* Start of inlined file: juce_FillType.h *********/ -#ifndef __JUCE_FILLTYPE_JUCEHEADER__ -#define __JUCE_FILLTYPE_JUCEHEADER__ + forcedinline void desaturate() throw() + { + if (components.a < 0xff && components.a > 0) + { + const int newUnpremultipliedLevel = (0xff * ((int) components.r + (int) components.g + (int) components.b) / (3 * components.a)); -/********* Start of inlined file: juce_ColourGradient.h *********/ -#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ -#define __JUCE_COLOURGRADIENT_JUCEHEADER__ + components.r = components.g = components.b + = (uint8) ((newUnpremultipliedLevel * components.a + 0x7f) >> 8); + } + else + { + components.r = components.g = components.b + = (uint8) (((int) components.r + (int) components.g + (int) components.b) / 3); + } + } + + /** The indexes of the different components in the byte layout of this type of colour. */ + #if JUCE_BIG_ENDIAN + enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 }; + #else + enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 }; + #endif + +private: + + union + { + uint32 argb; + + struct + { +#if JUCE_BIG_ENDIAN + uint8 a : 8, r : 8, g : 8, b : 8; +#else + uint8 b, g, r, a; +#endif + } PACKED components; + }; + +} PACKED; /** - Describes the layout and colours that should be used to paint a colour gradient. + Represents a 24-bit RGB pixel, and can perform compositing operations on it. - @see Graphics::setGradientFill + This is used internally by the imaging classes. + + @see PixelARGB */ -class JUCE_API ColourGradient +class JUCE_API PixelRGB { public: + /** Creates a pixel without defining its colour. */ + PixelRGB() throw() {} + ~PixelRGB() throw() {} - /** Creates a gradient object. - - (x1, y1) is the location to draw with colour1. Likewise (x2, y2) is where - colour2 should be. In between them there's a gradient. + /** Creates a pixel from a 32-bit argb value. - If isRadial is true, the colours form a circular gradient with (x1, y1) at - its centre. + (The argb format is that used by PixelARGB) + */ + PixelRGB (const uint32 argb) throw() + { + r = (uint8) (argb >> 16); + g = (uint8) (argb >> 8); + b = (uint8) (argb); + } - The alpha transparencies of the colours are used, so note that - if you blend from transparent to a solid colour, the RGB of the transparent - colour will become visible in parts of the gradient. e.g. blending - from Colour::transparentBlack to Colours::white will produce a - muddy grey colour midway, but Colour::transparentWhite to Colours::white - will be white all the way across. + forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } + forcedinline uint32 getRB() const throw() { return b | (uint32) (r << 16); } + forcedinline uint32 getAG() const throw() { return 0xff0000 | g; } - @see ColourGradient - */ - ColourGradient (const Colour& colour1, - const float x1, - const float y1, - const Colour& colour2, - const float x2, - const float y2, - const bool isRadial) throw(); + forcedinline uint8 getAlpha() const throw() { return 0xff; } + forcedinline uint8 getRed() const throw() { return r; } + forcedinline uint8 getGreen() const throw() { return g; } + forcedinline uint8 getBlue() const throw() { return b; } - /** Creates an uninitialised gradient. + /** Blends another pixel onto this one. - If you use this constructor instead of the other one, be sure to set all the - object's public member variables before using it! + This takes into account the opacity of the pixel being overlaid, and blends + it accordingly. */ - ColourGradient() throw(); + forcedinline void blend (const PixelARGB& src) throw() + { + uint32 sargb = src.getARGB(); + const uint32 alpha = 0x100 - (sargb >> 24); - /** Destructor */ - ~ColourGradient() throw(); + sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); + sargb += 0x0000ff00 & (g * alpha); - /** Removes any colours that have been added. + r = (uint8) (sargb >> 16); + g = (uint8) (sargb >> 8); + b = (uint8) sargb; + } - This will also remove any start and end colours, so the gradient won't work. You'll - need to add more colours with addColour(). - */ - void clearColours() throw(); + forcedinline void blend (const PixelRGB& src) throw() + { + set (src); + } - /** Adds a colour at a point along the length of the gradient. + forcedinline void blend (const PixelAlpha& src) throw(); - This allows the gradient to go through a spectrum of colours, instead of just a - start and end colour. + /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - @param proportionAlongGradient a value between 0 and 1.0, which is the proportion - of the distance along the line between the two points - at which the colour should occur. - @param colour the colour that should be used at this point + The opacity of the pixel being overlaid is scaled by the extraAlpha factor before + being used, so this can blend semi-transparently from a PixelRGB argument. */ - void addColour (const double proportionAlongGradient, - const Colour& colour) throw(); + template + forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() + { + ++extraAlpha; + const uint32 srb = (extraAlpha * src.getRB()) >> 8; + const uint32 sag = extraAlpha * src.getAG(); + uint32 sargb = (sag & 0xff00ff00) | (srb & 0x00ff00ff); - /** Multiplies the alpha value of all the colours by the given scale factor */ - void multiplyOpacity (const float multiplier) throw(); + const uint32 alpha = 0x100 - (sargb >> 24); - /** Returns the number of colour-stops that have been added. */ - int getNumColours() const throw(); + sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); + sargb += 0x0000ff00 & (g * alpha); - /** Returns the position along the length of the gradient of the colour with this index. + b = (uint8) sargb; + g = (uint8) (sargb >> 8); + r = (uint8) (sargb >> 16); + } - The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 + /** Blends another pixel with this one, creating a colour that is somewhere + between the two, as specified by the amount. */ - double getColourPosition (const int index) const throw(); - - /** Returns the colour that was added with a given index. + template + forcedinline void tween (const Pixel& src, const uint32 amount) throw() + { + uint32 drb = getRB(); + drb += (((src.getRB() - drb) * amount) >> 8); - The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 - */ - const Colour getColour (const int index) const throw(); + uint32 dag = getAG(); + dag += (((src.getAG() - dag) * amount) >> 8); - /** Returns the an interpolated colour at any position along the gradient. - @param position the position along the gradient, between 0 and 1 - */ - const Colour getColourAtPosition (const float position) const throw(); + b = (uint8) drb; + g = (uint8) dag; + r = (uint8) (drb >> 16); + } - /** Creates a set of interpolated premultiplied ARGB values. + /** Copies another pixel colour over this one. - The caller must delete the array that is returned using juce_free(). + This doesn't blend it - this colour is simply replaced by the other one. + Because PixelRGB has no alpha channel, any alpha value in the source pixel + is thrown away. */ - PixelARGB* createLookupTable (const AffineTransform& transform, int& numEntries) const throw(); + template + forcedinline void set (const Pixel& src) throw() + { + b = src.getBlue(); + g = src.getGreen(); + r = src.getRed(); + } - /** Returns true if all colours are opaque. */ - bool isOpaque() const throw(); + /** This method is included for compatibility with the PixelARGB class. */ + forcedinline void setAlpha (const uint8) throw() {} - /** Returns true if all colours are completely transparent. */ - bool isInvisible() const throw(); + /** Multiplies the colour's alpha value with another one. */ + forcedinline void multiplyAlpha (int) throw() {} - float x1; - float y1; + /** Sets the pixel's colour from individual components. */ + void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) throw() + { + r = r_; + g = g_; + b = b_; + } - float x2; - float y2; + /** Premultiplies the pixel's RGB values by its alpha. */ + forcedinline void premultiply() throw() {} - /** If true, the gradient should be filled circularly, centred around - (x1, y1), with (x2, y2) defining a point on the circumference. + /** Unpremultiplies the pixel's RGB values. */ + forcedinline void unpremultiply() throw() {} - If false, the gradient is linear between the two points. - */ - bool isRadial; + forcedinline void desaturate() throw() + { + r = g = b = (uint8) (((int) r + (int) g + (int) b) / 3); + } - juce_UseDebuggingNewOperator + /** The indexes of the different components in the byte layout of this type of colour. */ + #if JUCE_MAC + enum { indexR = 0, indexG = 1, indexB = 2 }; + #else + enum { indexR = 2, indexG = 1, indexB = 0 }; + #endif private: - Array colours; -}; -#endif // __JUCE_COLOURGRADIENT_JUCEHEADER__ -/********* End of inlined file: juce_ColourGradient.h *********/ +#if JUCE_MAC + uint8 r, g, b; +#else + uint8 b, g, r; +#endif -class Image; +} PACKED; -/** - Represents a colour or fill pattern to use for rendering paths. +forcedinline void PixelARGB::blend (const PixelRGB& src) throw() +{ + set (src); +} - This is used by the Graphics and DrawablePath classes as a way to encapsulate - a brush type. It can either be a solid colour, a gradient, or a tiled image. +/** + Represents an 8-bit single-channel pixel, and can perform compositing operations on it. - @see Graphics::setFillType, DrawablePath::setFill + This is used internally by the imaging classes. + + @see PixelARGB, PixelRGB */ -class JUCE_API FillType +class JUCE_API PixelAlpha { public: - /** Creates a default fill type, of solid black. */ - FillType() throw(); - - /** Creates a fill type of a solid colour. - @see setColour - */ - FillType (const Colour& colour) throw(); + /** Creates a pixel without defining its colour. */ + PixelAlpha() throw() {} + ~PixelAlpha() throw() {} - /** Creates a gradient fill type. - @see setGradient - */ - FillType (const ColourGradient& gradient) throw(); + /** Creates a pixel from a 32-bit argb value. - /** Creates a tiled image fill type. The transform allows you to set the scaling, offset - and rotation of the pattern. - @see setTiledImage + (The argb format is that used by PixelARGB) */ - FillType (const Image& image, const AffineTransform& transform) throw(); - - /** Creates a copy of another FillType. */ - FillType (const FillType& other) throw(); - - /** Makes a copy of another FillType. */ - const FillType& operator= (const FillType& other) throw(); - - /** Destructor. */ - ~FillType() throw(); + PixelAlpha (const uint32 argb) throw() + { + a = (uint8) (argb >> 24); + } - /** Returns true if this is a solid colour fill, and not a gradient or image. */ - bool isColour() const throw() { return gradient == 0 && image == 0; } + forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } + forcedinline uint32 getRB() const throw() { return (((uint32) a) << 16) | a; } + forcedinline uint32 getAG() const throw() { return (((uint32) a) << 16) | a; } - /** Returns true if this is a gradient fill. */ - bool isGradient() const throw() { return gradient != 0; } + forcedinline uint8 getAlpha() const throw() { return a; } + forcedinline uint8 getRed() const throw() { return 0; } + forcedinline uint8 getGreen() const throw() { return 0; } + forcedinline uint8 getBlue() const throw() { return 0; } - /** Returns true if this is a tiled image pattern fill. */ - bool isTiledImage() const throw() { return image != 0; } + /** Blends another pixel onto this one. - /** Turns this object into a solid colour fill. - If the object was an image or gradient, those fields will no longer be valid. */ - void setColour (const Colour& newColour) throw(); + This takes into account the opacity of the pixel being overlaid, and blends + it accordingly. + */ + template + forcedinline void blend (const Pixel& src) throw() + { + const int srcA = src.getAlpha(); + a = (uint8) ((a * (0x100 - srcA) >> 8) + srcA); + } - /** Turns this object into a gradient fill. */ - void setGradient (const ColourGradient& newGradient) throw(); + /** Blends another pixel onto this one, applying an extra multiplier to its opacity. - /** Turns this object into a tiled image fill type. The transform allows you to set - the scaling, offset and rotation of the pattern. + The opacity of the pixel being overlaid is scaled by the extraAlpha factor before + being used, so this can blend semi-transparently from a PixelRGB argument. */ - void setTiledImage (const Image& image, const AffineTransform& transform) throw(); + template + forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() + { + ++extraAlpha; + const int srcAlpha = (extraAlpha * src.getAlpha()) >> 8; + a = (uint8) ((a * (0x100 - srcAlpha) >> 8) + srcAlpha); + } - /** Changes the opacity that should be used. - If the fill is a solid colour, this just changes the opacity of that colour. For - gradients and image tiles, it changes the opacity that will be used for them. + /** Blends another pixel with this one, creating a colour that is somewhere + between the two, as specified by the amount. */ - void setOpacity (const float newOpacity) throw(); + template + forcedinline void tween (const Pixel& src, const uint32 amount) throw() + { + a += ((src,getAlpha() - a) * amount) >> 8; + } - /** Returns the current opacity to be applied to the colour, gradient, or image. - @see setOpacity + /** Copies another pixel colour over this one. + + This doesn't blend it - this colour is simply replaced by the other one. */ - float getOpacity() const throw() { return colour.getFloatAlpha(); } + template + forcedinline void set (const Pixel& src) throw() + { + a = src.getAlpha(); + } - /** The solid colour being used. + /** Replaces the colour's alpha value with another one. */ + forcedinline void setAlpha (const uint8 newAlpha) throw() + { + a = newAlpha; + } - If the fill type is not a solid colour, the alpha channel of this colour indicates - the opacity that should be used for the fill, and the RGB channels are ignored. - */ - Colour colour; + /** Multiplies the colour's alpha value with another one. */ + forcedinline void multiplyAlpha (int multiplier) throw() + { + ++multiplier; + a = (uint8) ((a * multiplier) >> 8); + } - /** Returns the gradient that should be used for filling. - This will be zero if the object is some other type of fill. - If a gradient is active, the overall opacity with which it should be applied - is indicated by the alpha channel of the colour variable. - */ - ColourGradient* gradient; + forcedinline void multiplyAlpha (const float multiplier) throw() + { + a = (uint8) (a * multiplier); + } - /** Returns the image that should be used for tiling. - The FillType object just keeps a pointer to this image, it doesn't own it, so you have to - be careful to make sure the image doesn't get deleted while it's being used. - If an image fill is active, the overall opacity with which it should be applied - is indicated by the alpha channel of the colour variable. - */ - const Image* image; + /** Sets the pixel's colour from individual components. */ + forcedinline void setARGB (const uint8 a_, const uint8 r, const uint8 g, const uint8 b) throw() + { + a = a_; + } - /** The transform that should be applied to the image or gradient that's being drawn. - */ - AffineTransform transform; + /** Premultiplies the pixel's RGB values by its alpha. */ + forcedinline void premultiply() throw() + { + } - juce_UseDebuggingNewOperator -}; + /** Unpremultiplies the pixel's RGB values. */ + forcedinline void unpremultiply() throw() + { + } -#endif // __JUCE_FILLTYPE_JUCEHEADER__ -/********* End of inlined file: juce_FillType.h *********/ + forcedinline void desaturate() throw() + { + } -/********* Start of inlined file: juce_RectanglePlacement.h *********/ -#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ -#define __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ +private: -/** - Defines the method used to postion some kind of rectangular object within - a rectangular viewport. + uint8 a : 8; +} PACKED; - Although similar to Justification, this is more specific, and has some extra - options. -*/ -class JUCE_API RectanglePlacement +forcedinline void PixelRGB::blend (const PixelAlpha& src) throw() { -public: + blend (PixelARGB (src.getARGB())); +} - /** Creates a RectanglePlacement object using a combination of flags. */ - inline RectanglePlacement (const int flags_) throw() : flags (flags_) {} +forcedinline void PixelARGB::blend (const PixelAlpha& src) throw() +{ + uint32 sargb = src.getARGB(); + const uint32 alpha = 0x100 - (sargb >> 24); - /** Creates a copy of another Justification object. */ - RectanglePlacement (const RectanglePlacement& other) throw(); + sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); + sargb += 0xff00ff00 & (getAG() * alpha); - /** Copies another Justification object. */ - const RectanglePlacement& operator= (const RectanglePlacement& other) throw(); + argb = sargb; +} - /** Flag values that can be combined and used in the constructor. */ - enum - { +#if JUCE_MSVC + #pragma pack (pop) +#endif - /** Indicates that the source rectangle's left edge should be aligned with the left edge of the target rectangle. */ - xLeft = 1, +#undef PACKED - /** Indicates that the source rectangle's right edge should be aligned with the right edge of the target rectangle. */ - xRight = 2, +#endif // __JUCE_PIXELFORMATS_JUCEHEADER__ +/********* End of inlined file: juce_PixelFormats.h *********/ - /** Indicates that the source should be placed in the centre between the left and right - sides of the available space. */ - xMid = 4, +/** + Represents a colour, also including a transparency value. - /** Indicates that the source's top edge should be aligned with the top edge of the - destination rectangle. */ - yTop = 8, + The colour is stored internally as unsigned 8-bit red, green, blue and alpha values. +*/ +class JUCE_API Colour +{ +public: - /** Indicates that the source's bottom edge should be aligned with the bottom edge of the - destination rectangle. */ - yBottom = 16, + /** Creates a transparent black colour. */ + Colour() throw(); - /** Indicates that the source should be placed in the centre between the top and bottom - sides of the available space. */ - yMid = 32, + /** Creates a copy of another Colour object. */ + Colour (const Colour& other) throw(); - /** If this flag is set, then the source rectangle will be resized to completely fill - the destination rectangle, and all other flags are ignored. - */ - stretchToFit = 64, + /** Creates a colour from a 32-bit ARGB value. - /** If this flag is set, then the source rectangle will be resized so that it is the - minimum size to completely fill the destination rectangle, without changing its - aspect ratio. This means that some of the source rectangle may fall outside - the destination. + The format of this number is: + ((alpha << 24) | (red << 16) | (green << 8) | blue). - If this flag is not set, the source will be given the maximum size at which none - of it falls outside the destination rectangle. - */ - fillDestination = 128, + All components in the range 0x00 to 0xff. + An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. - /** Indicates that the source rectangle can be reduced in size if required, but should - never be made larger than its original size. - */ - onlyReduceInSize = 256, + @see getPixelARGB + */ + explicit Colour (const uint32 argb) throw(); - /** Indicates that the source rectangle can be enlarged if required, but should - never be made smaller than its original size. - */ - onlyIncreaseInSize = 512, + /** Creates an opaque colour using 8-bit red, green and blue values */ + Colour (const uint8 red, + const uint8 green, + const uint8 blue) throw(); - /** Indicates that the source rectangle's size should be left unchanged. - */ - doNotResize = (onlyIncreaseInSize | onlyReduceInSize), + /** Creates an opaque colour using 8-bit red, green and blue values */ + static const Colour fromRGB (const uint8 red, + const uint8 green, + const uint8 blue) throw(); - /** A shorthand value that is equivalent to (xMid | yMid). */ - centred = 4 + 32 - }; + /** Creates a colour using 8-bit red, green, blue and alpha values. */ + Colour (const uint8 red, + const uint8 green, + const uint8 blue, + const uint8 alpha) throw(); - /** Returns the raw flags that are set for this object. */ - inline int getFlags() const throw() { return flags; } + /** Creates a colour using 8-bit red, green, blue and alpha values. */ + static const Colour fromRGBA (const uint8 red, + const uint8 green, + const uint8 blue, + const uint8 alpha) throw(); - /** Tests a set of flags for this object. + /** Creates a colour from 8-bit red, green, and blue values, and a floating-point alpha. - @returns true if any of the flags passed in are set on this object. + Alpha of 0.0 is transparent, alpha of 1.0f is opaque. + Values outside the valid range will be clipped. */ - inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } + Colour (const uint8 red, + const uint8 green, + const uint8 blue, + const float alpha) throw(); - /** Adjusts the position and size of a rectangle to fit it into a space. + /** Creates a colour using 8-bit red, green, blue and float alpha values. */ + static const Colour fromRGBAFloat (const uint8 red, + const uint8 green, + const uint8 blue, + const float alpha) throw(); - The source rectangle co-ordinates will be adjusted so that they fit into - the destination rectangle based on this object's flags. - */ - void applyTo (double& sourceX, - double& sourceY, - double& sourceW, - double& sourceH, - const double destinationX, - const double destinationY, - const double destinationW, - const double destinationH) const throw(); + /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. - /** Returns the transform that should be applied to these source co-ordinates to fit them - into the destination rectangle using the current flags. + The floating point values must be between 0.0 and 1.0. + An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. + Values outside the valid range will be clipped. */ - const AffineTransform getTransformToFit (float sourceX, - float sourceY, - float sourceW, - float sourceH, - const float destinationX, - const float destinationY, - const float destinationW, - const float destinationH) const throw(); + Colour (const float hue, + const float saturation, + const float brightness, + const uint8 alpha) throw(); -private: + /** Creates a colour using floating point hue, saturation, brightness and alpha values. - int flags; -}; + All values must be between 0.0 and 1.0. + Numbers outside the valid range will be clipped. + */ + Colour (const float hue, + const float saturation, + const float brightness, + const float alpha) throw(); -#endif // __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ -/********* End of inlined file: juce_RectanglePlacement.h *********/ + /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. -class LowLevelGraphicsContext; -class Image; -class RectangleList; + The floating point values must be between 0.0 and 1.0. + An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. + Values outside the valid range will be clipped. + */ + static const Colour fromHSV (const float hue, + const float saturation, + const float brightness, + const float alpha) throw(); -/** - A graphics context, used for drawing a component or image. + /** Destructor. */ + ~Colour() throw(); - When a Component needs painting, a Graphics context is passed to its - Component::paint() method, and this you then call methods within this - object to actually draw the component's content. + /** Copies another Colour object. */ + const Colour& operator= (const Colour& other) throw(); - A Graphics can also be created from an image, to allow drawing directly onto - that image. + /** Compares two colours. */ + bool operator== (const Colour& other) const throw(); + /** Compares two colours. */ + bool operator!= (const Colour& other) const throw(); - @see Component::paint -*/ -class JUCE_API Graphics -{ -public: + /** Returns the red component of this colour. - /** Creates a Graphics object to draw directly onto the given image. + @returns a value between 0x00 and 0xff. + */ + uint8 getRed() const throw() { return argb.getRed(); } - The graphics object that is created will be set up to draw onto the image, - with the context's clipping area being the entire size of the image, and its - origin being the image's origin. To draw into a subsection of an image, use the - reduceClipRegion() and setOrigin() methods. + /** Returns the green component of this colour. - Obviously you shouldn't delete the image before this context is deleted. + @returns a value between 0x00 and 0xff. */ - Graphics (Image& imageToDrawOnto) throw(); - - /** Destructor. */ - ~Graphics() throw(); + uint8 getGreen() const throw() { return argb.getGreen(); } - /** Changes the current drawing colour. + /** Returns the blue component of this colour. - This sets the colour that will now be used for drawing operations - it also - sets the opacity to that of the colour passed-in. + @returns a value between 0x00 and 0xff. + */ + uint8 getBlue() const throw() { return argb.getBlue(); } - If a brush is being used when this method is called, the brush will be deselected, - and any subsequent drawing will be done with a solid colour brush instead. + /** Returns the red component of this colour as a floating point value. - @see setOpacity + @returns a value between 0.0 and 1.0 */ - void setColour (const Colour& newColour) throw(); + float getFloatRed() const throw(); - /** Changes the opacity to use with the current colour. + /** Returns the green component of this colour as a floating point value. - If a solid colour is being used for drawing, this changes its opacity - to this new value (i.e. it doesn't multiply the colour's opacity by this amount). + @returns a value between 0.0 and 1.0 + */ + float getFloatGreen() const throw(); - If a gradient is being used, this will have no effect on it. + /** Returns the blue component of this colour as a floating point value. - A value of 0.0 is completely transparent, 1.0 is completely opaque. + @returns a value between 0.0 and 1.0 */ - void setOpacity (const float newOpacity) throw(); + float getFloatBlue() const throw(); - /** Sets the context to use a gradient for its fill pattern. + /** Returns a premultiplied ARGB pixel object that represents this colour. */ - void setGradientFill (const ColourGradient& gradient) throw(); + const PixelARGB getPixelARGB() const throw(); - /** Sets the context to use a tiled image pattern for filling. - Make sure that you don't delete this image while it's still being used by - this context! - */ - void setTiledImageFill (const Image& imageToUse, - const int anchorX, - const int anchorY, - const float opacity) throw(); + /** Returns a 32-bit integer that represents this colour. - /** Changes the current fill settings. - @see setColour, setGradientFill, setTiledImageFill + The format of this number is: + ((alpha << 24) | (red << 16) | (green << 16) | blue). */ - void setFillType (const FillType& newFill) throw(); - - /** Changes the font to use for subsequent text-drawing functions. + uint32 getARGB() const throw(); - Note there's also a setFont (float, int) method to quickly change the size and - style of the current font. + /** Returns the colour's alpha (opacity). - @see drawSingleLineText, drawMultiLineText, drawTextAsPath, drawText, drawFittedText + Alpha of 0x00 is completely transparent, 0xff is completely opaque. */ - void setFont (const Font& newFont) throw(); - - /** Changes the size and style of the currently-selected font. + uint8 getAlpha() const throw() { return argb.getAlpha(); } - This is a convenient shortcut that changes the context's current font to a - different size or style. The typeface won't be changed. + /** Returns the colour's alpha (opacity) as a floating point value. - @see Font + Alpha of 0.0 is completely transparent, 1.0 is completely opaque. */ - void setFont (const float newFontHeight, - const int fontStyleFlags = Font::plain) throw(); - - /** Draws a one-line text string. + float getFloatAlpha() const throw(); - This will use the current colour (or brush) to fill the text. The font is the last - one specified by setFont(). + /** Returns true if this colour is completely opaque. - @param text the string to draw - @param startX the position to draw the left-hand edge of the text - @param baselineY the position of the text's baseline - @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText + Equivalent to (getAlpha() == 0xff). */ - void drawSingleLineText (const String& text, - const int startX, - const int baselineY) const throw(); - - /** Draws text across multiple lines. + bool isOpaque() const throw(); - This will break the text onto a new line where there's a new-line or - carriage-return character, or at a word-boundary when the text becomes wider - than the size specified by the maximumLineWidth parameter. + /** Returns true if this colour is completely transparent. - @see setFont, drawSingleLineText, drawFittedText, GlyphArrangement::addJustifiedText + Equivalent to (getAlpha() == 0x00). */ - void drawMultiLineText (const String& text, - const int startX, - const int baselineY, - const int maximumLineWidth) const throw(); + bool isTransparent() const throw(); - /** Renders a string of text as a vector path. + /** Returns a colour that's the same colour as this one, but with a new alpha value. */ + const Colour withAlpha (const uint8 newAlpha) const throw(); - This allows a string to be transformed with an arbitrary AffineTransform and - rendered using the current colour/brush. It's much slower than the normal text methods - but more accurate. + /** Returns a colour that's the same colour as this one, but with a new alpha value. */ + const Colour withAlpha (const float newAlpha) const throw(); - @see setFont + /** Returns a colour that's the same colour as this one, but with a modified alpha value. + + The new colour's alpha will be this object's alpha multiplied by the value passed-in. */ - void drawTextAsPath (const String& text, - const AffineTransform& transform) const throw(); + const Colour withMultipliedAlpha (const float alphaMultiplier) const throw(); - /** Draws a line of text within a specified rectangle. + /** Returns a colour that is the result of alpha-compositing a new colour over this one. - The text will be positioned within the rectangle based on the justification - flags passed-in. If the string is too long to fit inside the rectangle, it will - either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig - flag is true). + If the foreground colour is semi-transparent, it is blended onto this colour + accordingly. + */ + const Colour overlaidWith (const Colour& foregroundColour) const throw(); - @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText + /** Returns a colour that lies somewhere between this one and another. + + If amountOfOther is zero, the result is 100% this colour, if amountOfOther + is 1.0, the result is 100% of the other colour. */ - void drawText (const String& text, - const int x, - const int y, - const int width, - const int height, - const Justification& justificationType, - const bool useEllipsesIfTooBig) const throw(); + const Colour interpolatedWith (const Colour& other, float proportionOfOther) const throw(); - /** Tries to draw a text string inside a given space. + /** Returns the colour's hue component. + The value returned is in the range 0.0 to 1.0 + */ + float getHue() const throw(); - This does its best to make the given text readable within the specified rectangle, - so it useful for labelling things. + /** Returns the colour's saturation component. + The value returned is in the range 0.0 to 1.0 + */ + float getSaturation() const throw(); - If the text is too big, it'll be squashed horizontally or broken over multiple lines - if the maximumLinesToUse value allows this. If the text just won't fit into the space, - it'll cram as much as possible in there, and put some ellipsis at the end to show that - it's been truncated. + /** Returns the colour's brightness component. + The value returned is in the range 0.0 to 1.0 + */ + float getBrightness() const throw(); - A Justification parameter lets you specify how the text is laid out within the rectangle, - both horizontally and vertically. + /** Returns the colour's hue, saturation and brightness components all at once. + The values returned are in the range 0.0 to 1.0 + */ + void getHSB (float& hue, + float& saturation, + float& brightness) const throw(); - The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally - to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you - can set this value to 1.0f. + /** Returns a copy of this colour with a different hue. */ + const Colour withHue (const float newHue) const throw(); - @see GlyphArrangement::addFittedText + /** Returns a copy of this colour with a different saturation. */ + const Colour withSaturation (const float newSaturation) const throw(); + + /** Returns a copy of this colour with a different brightness. + @see brighter, darker, withMultipliedBrightness */ - void drawFittedText (const String& text, - const int x, - const int y, - const int width, - const int height, - const Justification& justificationFlags, - const int maximumNumberOfLines, - const float minimumHorizontalScale = 0.7f) const throw(); + const Colour withBrightness (const float newBrightness) const throw(); - /** Fills the context's entire clip region with the current colour or brush. + /** Returns a copy of this colour with it hue rotated. - (See also the fillAll (const Colour&) method which is a quick way of filling - it with a given colour). + The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) + + @see brighter, darker, withMultipliedBrightness */ - void fillAll() const throw(); + const Colour withRotatedHue (const float amountToRotate) const throw(); - /** Fills the context's entire clip region with a given colour. + /** Returns a copy of this colour with its saturation multiplied by the given value. - This leaves the context's current colour and brush unchanged, it just - uses the specified colour temporarily. + The new colour's saturation is (this->getSaturation() * multiplier) + (the result is clipped to legal limits). */ - void fillAll (const Colour& colourToUse) const throw(); + const Colour withMultipliedSaturation (const float multiplier) const throw(); - /** Fills a rectangle with the current colour or brush. + /** Returns a copy of this colour with its brightness multiplied by the given value. - @see drawRect, fillRoundedRectangle + The new colour's saturation is (this->getBrightness() * multiplier) + (the result is clipped to legal limits). */ - void fillRect (int x, - int y, - int width, - int height) const throw(); + const Colour withMultipliedBrightness (const float amount) const throw(); - /** Fills a rectangle with the current colour or brush. */ - void fillRect (const Rectangle& rectangle) const throw(); + /** Returns a brighter version of this colour. - /** Fills a rectangle with the current colour or brush. + @param amountBrighter how much brighter to make it - a value from 0 to 1.0 where 0 is + unchanged, and higher values make it brighter + @see withMultipliedBrightness + */ + const Colour brighter (float amountBrighter = 0.4f) const throw(); - This uses sub-pixel positioning so is slower than the fillRect method which - takes integer co-ordinates. + /** Returns a darker version of this colour. + + @param amountDarker how much darker to make it - a value from 0 to 1.0 where 0 is + unchanged, and higher values make it darker + @see withMultipliedBrightness */ - void fillRect (const float x, - const float y, - const float width, - const float height) const throw(); + const Colour darker (float amountDarker = 0.4f) const throw(); - /** Uses the current colour or brush to fill a rectangle with rounded corners. + /** Returns a colour that will be clearly visible against this colour. - @see drawRoundedRectangle, Path::addRoundedRectangle + The amount parameter indicates how contrasting the new colour should + be, so e.g. Colours::black.contrasting (0.1f) will return a colour + that's just a little bit lighter; Colours::black.contrasting (1.0f) will + return white; Colours::white.contrasting (1.0f) will return black, etc. */ - void fillRoundedRectangle (const float x, - const float y, - const float width, - const float height, - const float cornerSize) const throw(); + const Colour contrasting (const float amount = 1.0f) const throw(); - /** Uses the current colour or brush to fill a rectangle with rounded corners. + /** Returns a colour that contrasts against two colours. - @see drawRoundedRectangle, Path::addRoundedRectangle + Looks for a colour that contrasts with both of the colours passed-in. + + Handy for things like choosing a highlight colour in text editors, etc. */ - void fillRoundedRectangle (const Rectangle& rectangle, - const float cornerSize) const throw(); + static const Colour contrasting (const Colour& colour1, + const Colour& colour2) throw(); - /** Fills a rectangle with a checkerboard pattern, alternating between two colours. + /** Returns an opaque shade of grey. + + @param brightness the level of grey to return - 0 is black, 1.0 is white */ - void fillCheckerBoard (int x, int y, - int width, int height, - const int checkWidth, - const int checkHeight, - const Colour& colour1, - const Colour& colour2) const throw(); + static const Colour greyLevel (const float brightness) throw(); - /** Draws four lines to form a rectangular outline, using the current colour or brush. + /** Returns a stringified version of this colour. - The lines are drawn inside the given rectangle, and greater line thicknesses - extend inwards. + The string can be turned back into a colour using the fromString() method. + */ + const String toString() const throw(); - @see fillRect + /** Reads the colour from a string that was created with toString(). */ - void drawRect (const int x, - const int y, - const int width, - const int height, - const int lineThickness = 1) const throw(); + static const Colour fromString (const String& encodedColourString); - /** Draws four lines to form a rectangular outline, using the current colour or brush. + juce_UseDebuggingNewOperator - The lines are drawn inside the given rectangle, and greater line thicknesses - extend inwards. +private: + PixelARGB argb; +}; - @see fillRect - */ - void drawRect (const float x, - const float y, - const float width, - const float height, - const float lineThickness = 1.0f) const throw(); +#endif // __JUCE_COLOUR_JUCEHEADER__ +/********* End of inlined file: juce_Colour.h *********/ - /** Draws four lines to form a rectangular outline, using the current colour or brush. +/** + Contains a set of predefined named colours (mostly standard HTML colours) - The lines are drawn inside the given rectangle, and greater line thicknesses - extend inwards. + @see Colour, Colours::greyLevel +*/ +class Colours +{ +public: + static JUCE_API const Colour - @see fillRect - */ - void drawRect (const Rectangle& rectangle, - const int lineThickness = 1) const throw(); + transparentBlack, /**< ARGB = 0x00000000 */ + transparentWhite, /**< ARGB = 0x00ffffff */ - /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. + black, /**< ARGB = 0xff000000 */ + white, /**< ARGB = 0xffffffff */ + blue, /**< ARGB = 0xff0000ff */ + grey, /**< ARGB = 0xff808080 */ + green, /**< ARGB = 0xff008000 */ + red, /**< ARGB = 0xffff0000 */ + yellow, /**< ARGB = 0xffffff00 */ - @see fillRoundedRectangle, Path::addRoundedRectangle - */ - void drawRoundedRectangle (const float x, - const float y, - const float width, - const float height, - const float cornerSize, - const float lineThickness) const throw(); + aliceblue, antiquewhite, aqua, aquamarine, + azure, beige, bisque, blanchedalmond, + blueviolet, brown, burlywood, cadetblue, + chartreuse, chocolate, coral, cornflowerblue, + cornsilk, crimson, cyan, darkblue, + darkcyan, darkgoldenrod, darkgrey, darkgreen, + darkkhaki, darkmagenta, darkolivegreen, darkorange, + darkorchid, darkred, darksalmon, darkseagreen, + darkslateblue, darkslategrey, darkturquoise, darkviolet, + deeppink, deepskyblue, dimgrey, dodgerblue, + firebrick, floralwhite, forestgreen, fuchsia, + gainsboro, gold, goldenrod, greenyellow, + honeydew, hotpink, indianred, indigo, + ivory, khaki, lavender, lavenderblush, + lemonchiffon, lightblue, lightcoral, lightcyan, + lightgoldenrodyellow, lightgreen, lightgrey, lightpink, + lightsalmon, lightseagreen, lightskyblue, lightslategrey, + lightsteelblue, lightyellow, lime, limegreen, + linen, magenta, maroon, mediumaquamarine, + mediumblue, mediumorchid, mediumpurple, mediumseagreen, + mediumslateblue, mediumspringgreen, mediumturquoise, mediumvioletred, + midnightblue, mintcream, mistyrose, navajowhite, + navy, oldlace, olive, olivedrab, + orange, orangered, orchid, palegoldenrod, + palegreen, paleturquoise, palevioletred, papayawhip, + peachpuff, peru, pink, plum, + powderblue, purple, rosybrown, royalblue, + saddlebrown, salmon, sandybrown, seagreen, + seashell, sienna, silver, skyblue, + slateblue, slategrey, snow, springgreen, + steelblue, tan, teal, thistle, + tomato, turquoise, violet, wheat, + whitesmoke, yellowgreen; - /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. + /** Attempts to look up a string in the list of known colour names, and return + the appropriate colour. - @see fillRoundedRectangle, Path::addRoundedRectangle + A non-case-sensitive search is made of the list of predefined colours, and + if a match is found, that colour is returned. If no match is found, the + colour passed in as the defaultColour parameter is returned. */ - void drawRoundedRectangle (const Rectangle& rectangle, - const float cornerSize, - const float lineThickness) const throw(); + static JUCE_API const Colour findColourForName (const String& colourName, + const Colour& defaultColour); - /** Draws a 3D raised (or indented) bevel using two colours. +private: - The bevel is drawn inside the given rectangle, and greater bevel thicknesses - extend inwards. + // this isn't a class you should ever instantiate - it's just here for the + // static values in it. + Colours(); +}; - The top-left colour is used for the top- and left-hand edges of the - bevel; the bottom-right colour is used for the bottom- and right-hand - edges. +#endif // __JUCE_COLOURS_JUCEHEADER__ +/********* End of inlined file: juce_Colours.h *********/ - If useGradient is true, then the bevel fades out to make it look more curved - and less angular. If sharpEdgeOnOutside is true, the outside of the bevel is - sharp, and it fades towards the centre; if sharpEdgeOnOutside is false, then - the centre edges are sharp and it fades towards the outside. - */ - void drawBevel (const int x, - const int y, - const int width, - const int height, - const int bevelThickness, - const Colour& topLeftColour = Colours::white, - const Colour& bottomRightColour = Colours::black, - const bool useGradient = true, - const bool sharpEdgeOnOutside = true) const throw(); +/********* Start of inlined file: juce_FillType.h *********/ +#ifndef __JUCE_FILLTYPE_JUCEHEADER__ +#define __JUCE_FILLTYPE_JUCEHEADER__ - /** Draws a pixel using the current colour or brush. - */ - void setPixel (int x, int y) const throw(); +/********* Start of inlined file: juce_ColourGradient.h *********/ +#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ +#define __JUCE_COLOURGRADIENT_JUCEHEADER__ - /** Fills an ellipse with the current colour or brush. +/** + Describes the layout and colours that should be used to paint a colour gradient. - The ellipse is drawn to fit inside the given rectangle. + @see Graphics::setGradientFill +*/ +class JUCE_API ColourGradient +{ +public: - @see drawEllipse, Path::addEllipse - */ - void fillEllipse (const float x, - const float y, - const float width, - const float height) const throw(); + /** Creates a gradient object. - /** Draws an elliptical stroke using the current colour or brush. + (x1, y1) is the location to draw with colour1. Likewise (x2, y2) is where + colour2 should be. In between them there's a gradient. - @see fillEllipse, Path::addEllipse - */ - void drawEllipse (const float x, - const float y, - const float width, - const float height, - const float lineThickness) const throw(); + If isRadial is true, the colours form a circular gradient with (x1, y1) at + its centre. - /** Draws a line between two points. + The alpha transparencies of the colours are used, so note that + if you blend from transparent to a solid colour, the RGB of the transparent + colour will become visible in parts of the gradient. e.g. blending + from Colour::transparentBlack to Colours::white will produce a + muddy grey colour midway, but Colour::transparentWhite to Colours::white + will be white all the way across. - The line is 1 pixel wide and drawn with the current colour or brush. + @see ColourGradient */ - void drawLine (float startX, - float startY, - float endX, - float endY) const throw(); + ColourGradient (const Colour& colour1, + const float x1, + const float y1, + const Colour& colour2, + const float x2, + const float y2, + const bool isRadial) throw(); - /** Draws a line between two points with a given thickness. + /** Creates an uninitialised gradient. - @see Path::addLineSegment + If you use this constructor instead of the other one, be sure to set all the + object's public member variables before using it! */ - void drawLine (const float startX, - const float startY, - const float endX, - const float endY, - const float lineThickness) const throw(); + ColourGradient() throw(); - /** Draws a line between two points. + /** Destructor */ + ~ColourGradient() throw(); - The line is 1 pixel wide and drawn with the current colour or brush. + /** Removes any colours that have been added. + + This will also remove any start and end colours, so the gradient won't work. You'll + need to add more colours with addColour(). */ - void drawLine (const Line& line) const throw(); + void clearColours() throw(); - /** Draws a line between two points with a given thickness. + /** Adds a colour at a point along the length of the gradient. - @see Path::addLineSegment + This allows the gradient to go through a spectrum of colours, instead of just a + start and end colour. + + @param proportionAlongGradient a value between 0 and 1.0, which is the proportion + of the distance along the line between the two points + at which the colour should occur. + @param colour the colour that should be used at this point */ - void drawLine (const Line& line, - const float lineThickness) const throw(); + void addColour (const double proportionAlongGradient, + const Colour& colour) throw(); - /** Draws a dashed line using a custom set of dash-lengths. + /** Multiplies the alpha value of all the colours by the given scale factor */ + void multiplyOpacity (const float multiplier) throw(); - @param startX the line's start x co-ordinate - @param startY the line's start y co-ordinate - @param endX the line's end x co-ordinate - @param endY the line's end y co-ordinate - @param dashLengths a series of lengths to specify the on/off lengths - e.g. - { 4, 5, 6, 7 } will draw a line of 4 pixels, skip 5 pixels, - draw 6 pixels, skip 7 pixels, and then repeat. - @param numDashLengths the number of elements in the array (this must be an even number). - @param lineThickness the thickness of the line to draw - @see PathStrokeType::createDashedStroke - */ - void drawDashedLine (const float startX, - const float startY, - const float endX, - const float endY, - const float* const dashLengths, - const int numDashLengths, - const float lineThickness = 1.0f) const throw(); + /** Returns the number of colour-stops that have been added. */ + int getNumColours() const throw(); - /** Draws a vertical line of pixels at a given x position. + /** Returns the position along the length of the gradient of the colour with this index. - The x position is an integer, but the top and bottom of the line can be sub-pixel - positions, and these will be anti-aliased if necessary. + The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 */ - void drawVerticalLine (const int x, float top, float bottom) const throw(); + double getColourPosition (const int index) const throw(); - /** Draws a horizontal line of pixels at a given y position. + /** Returns the colour that was added with a given index. - The y position is an integer, but the left and right ends of the line can be sub-pixel - positions, and these will be anti-aliased if necessary. + The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 */ - void drawHorizontalLine (const int y, float left, float right) const throw(); + const Colour getColour (const int index) const throw(); - /** Fills a path using the currently selected colour or brush. + /** Returns the an interpolated colour at any position along the gradient. + @param position the position along the gradient, between 0 and 1 */ - void fillPath (const Path& path, - const AffineTransform& transform = AffineTransform::identity) const throw(); + const Colour getColourAtPosition (const float position) const throw(); - /** Draws a path's outline using the currently selected colour or brush. + /** Creates a set of interpolated premultiplied ARGB values. + This will resize the HeapBlock, fill it with the colours, and will return the number of + colours that it added. */ - void strokePath (const Path& path, - const PathStrokeType& strokeType, - const AffineTransform& transform = AffineTransform::identity) const throw(); + int createLookupTable (const AffineTransform& transform, HeapBlock & resultLookupTable) const throw(); - /** Draws a line with an arrowhead. + /** Returns true if all colours are opaque. */ + bool isOpaque() const throw(); - @param startX the line's start x co-ordinate - @param startY the line's start y co-ordinate - @param endX the line's end x co-ordinate (the tip of the arrowhead) - @param endY the line's end y co-ordinate (the tip of the arrowhead) - @param lineThickness the thickness of the line - @param arrowheadWidth the width of the arrow head (perpendicular to the line) - @param arrowheadLength the length of the arrow head (along the length of the line) - */ - void drawArrow (const float startX, - const float startY, - const float endX, - const float endY, - const float lineThickness, - const float arrowheadWidth, - const float arrowheadLength) const throw(); + /** Returns true if all colours are completely transparent. */ + bool isInvisible() const throw(); - /** Types of rendering quality that can be specified when drawing images. + float x1; + float y1; - @see blendImage, Graphics::setImageResamplingQuality + float x2; + float y2; + + /** If true, the gradient should be filled circularly, centred around + (x1, y1), with (x2, y2) defining a point on the circumference. + + If false, the gradient is linear between the two points. */ - enum ResamplingQuality - { - lowResamplingQuality = 0, /**< Just uses a nearest-neighbour algorithm for resampling. */ - mediumResamplingQuality = 1, /**< Uses bilinear interpolation for upsampling and area-averaging for downsampling. */ - highResamplingQuality = 2 /**< Uses bicubic interpolation for upsampling and area-averaging for downsampling. */ - }; + bool isRadial; - /** Changes the quality that will be used when resampling images. + juce_UseDebuggingNewOperator - By default a Graphics object will be set to mediumRenderingQuality. +private: + Array colours; +}; - @see Graphics::drawImage, Graphics::drawImageTransformed, Graphics::drawImageWithin - */ - void setImageResamplingQuality (const ResamplingQuality newQuality) throw(); +#endif // __JUCE_COLOURGRADIENT_JUCEHEADER__ +/********* End of inlined file: juce_ColourGradient.h *********/ - /** Draws an image. +class Image; - This will draw the whole of an image, positioning its top-left corner at the - given co-ordinates, and keeping its size the same. This is the simplest image - drawing method - the others give more control over the scaling and clipping - of the images. +/** + Represents a colour or fill pattern to use for rendering paths. - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. + This is used by the Graphics and DrawablePath classes as a way to encapsulate + a brush type. It can either be a solid colour, a gradient, or a tiled image. + + @see Graphics::setFillType, DrawablePath::setFill +*/ +class JUCE_API FillType +{ +public: + /** Creates a default fill type, of solid black. */ + FillType() throw(); + + /** Creates a fill type of a solid colour. + @see setColour */ - void drawImageAt (const Image* const imageToDraw, - const int topLeftX, - const int topLeftY, - const bool fillAlphaChannelWithCurrentBrush = false) const throw(); + FillType (const Colour& colour) throw(); - /** Draws part of an image, rescaling it to fit in a given target region. + /** Creates a gradient fill type. + @see setGradient + */ + FillType (const ColourGradient& gradient) throw(); - The specified area of the source image is rescaled and drawn to fill the - specifed destination rectangle. + /** Creates a tiled image fill type. The transform allows you to set the scaling, offset + and rotation of the pattern. + @see setTiledImage + */ + FillType (const Image& image, const AffineTransform& transform) throw(); - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. + /** Creates a copy of another FillType. */ + FillType (const FillType& other) throw(); - @param imageToDraw the image to overlay - @param destX the left of the destination rectangle - @param destY the top of the destination rectangle - @param destWidth the width of the destination rectangle - @param destHeight the height of the destination rectangle - @param sourceX the left of the rectangle to copy from the source image - @param sourceY the top of the rectangle to copy from the source image - @param sourceWidth the width of the rectangle to copy from the source image - @param sourceHeight the height of the rectangle to copy from the source image - @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the source image's pixels, - the source image's alpha channel is used as a mask with - which to fill the destination using the current colour - or brush. (If the source is has no alpha channel, then - it will just fill the target with a solid rectangle) - @see setImageResamplingQuality, drawImageAt, drawImageWithin, fillAlphaMap - */ - void drawImage (const Image* const imageToDraw, - int destX, - int destY, - int destWidth, - int destHeight, - int sourceX, - int sourceY, - int sourceWidth, - int sourceHeight, - const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - - /** Draws part of an image, having applied an affine transform to it. - - This lets you throw the image around in some wacky ways, rotate it, shear, - scale it, etc. + /** Makes a copy of another FillType. */ + const FillType& operator= (const FillType& other) throw(); - A subregion is specified within the source image, and all transformations - will be treated as relative to the origin of this sub-region. So, for example if - your subregion is (50, 50, 100, 100), and your transform is a translation of (20, 20), - the resulting pixel drawn at (20, 20) in the destination context is from (50, 50) in - your image. If you want to use the whole image, then Image::getBounds() returns a - suitable rectangle to use as the imageSubRegion parameter. + /** Destructor. */ + ~FillType() throw(); - Images are composited using the context's current opacity, so if you - don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) - (or setColour() with an opaque colour) before drawing images. + /** Returns true if this is a solid colour fill, and not a gradient or image. */ + bool isColour() const throw() { return gradient == 0 && image == 0; } - If fillAlphaChannelWithCurrentBrush is set to true, then the image's RGB channels - are ignored and it is filled with the current brush, masked by its alpha channel. + /** Returns true if this is a gradient fill. */ + bool isGradient() const throw() { return gradient != 0; } - @see setImageResamplingQuality, drawImage - */ - void drawImageTransformed (const Image* const imageToDraw, - const Rectangle& imageSubRegion, - const AffineTransform& transform, - const bool fillAlphaChannelWithCurrentBrush = false) const throw(); + /** Returns true if this is a tiled image pattern fill. */ + bool isTiledImage() const throw() { return image != 0; } - /** Draws an image to fit within a designated rectangle. + /** Turns this object into a solid colour fill. + If the object was an image or gradient, those fields will no longer be valid. */ + void setColour (const Colour& newColour) throw(); - If the image is too big or too small for the space, it will be rescaled - to fit as nicely as it can do without affecting its aspect ratio. It will - then be placed within the target rectangle according to the justification flags - specified. + /** Turns this object into a gradient fill. */ + void setGradient (const ColourGradient& newGradient) throw(); - @param imageToDraw the source image to draw - @param destX top-left of the target rectangle to fit it into - @param destY top-left of the target rectangle to fit it into - @param destWidth size of the target rectangle to fit the image into - @param destHeight size of the target rectangle to fit the image into - @param placementWithinTarget this specifies how the image should be positioned - within the target rectangle - see the RectanglePlacement - class for more details about this. - @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the image, just its - alpha channel will be used as a mask with which to - draw with the current brush or colour. This is - similar to fillAlphaMap(), and see also drawImage() - @see setImageResamplingQuality, drawImage, drawImageTransformed, drawImageAt, RectanglePlacement + /** Turns this object into a tiled image fill type. The transform allows you to set + the scaling, offset and rotation of the pattern. */ - void drawImageWithin (const Image* const imageToDraw, - const int destX, - const int destY, - const int destWidth, - const int destHeight, - const RectanglePlacement& placementWithinTarget, - const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - - /** Returns the position of the bounding box for the current clipping region. + void setTiledImage (const Image& image, const AffineTransform& transform) throw(); - @see getClipRegion, clipRegionIntersects + /** Changes the opacity that should be used. + If the fill is a solid colour, this just changes the opacity of that colour. For + gradients and image tiles, it changes the opacity that will be used for them. */ - const Rectangle getClipBounds() const throw(); - - /** Checks whether a rectangle overlaps the context's clipping region. + void setOpacity (const float newOpacity) throw(); - If this returns false, no part of the given area can be drawn onto, so this - method can be used to optimise a component's paint() method, by letting it - avoid drawing complex objects that aren't within the region being repainted. + /** Returns the current opacity to be applied to the colour, gradient, or image. + @see setOpacity */ - bool clipRegionIntersects (const int x, const int y, const int width, const int height) const throw(); + float getOpacity() const throw() { return colour.getFloatAlpha(); } - /** Intersects the current clipping region with another region. + /** The solid colour being used. - @returns true if the resulting clipping region is non-zero in size - @see setOrigin, clipRegionIntersects + If the fill type is not a solid colour, the alpha channel of this colour indicates + the opacity that should be used for the fill, and the RGB channels are ignored. */ - bool reduceClipRegion (const int x, const int y, - const int width, const int height) throw(); - - /** Intersects the current clipping region with a rectangle list region. + Colour colour; - @returns true if the resulting clipping region is non-zero in size - @see setOrigin, clipRegionIntersects + /** Returns the gradient that should be used for filling. + This will be zero if the object is some other type of fill. + If a gradient is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ - bool reduceClipRegion (const RectangleList& clipRegion) throw(); - - /** Intersects the current clipping region with a path. + ColourGradient* gradient; - @returns true if the resulting clipping region is non-zero in size - @see reduceClipRegion + /** Returns the image that should be used for tiling. + The FillType object just keeps a pointer to this image, it doesn't own it, so you have to + be careful to make sure the image doesn't get deleted while it's being used. + If an image fill is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ - bool reduceClipRegion (const Path& path, const AffineTransform& transform = AffineTransform::identity) throw(); - - /** Intersects the current clipping region with an image's alpha-channel. - - The current clipping path is intersected with the area covered by this image's - alpha-channel, after the image has been transformed by the specified matrix. + const Image* image; - @param image the image whose alpha-channel should be used. If the image doesn't - have an alpha-channel, it is treated as entirely opaque. - @param sourceClipRegion a subsection of the image that should be used. To use the - entire image, just pass a rectangle of bounds - (0, 0, image.getWidth(), image.getHeight()). - @param transform a matrix to apply to the image - @returns true if the resulting clipping region is non-zero in size - @see reduceClipRegion + /** The transform that should be applied to the image or gradient that's being drawn. */ - bool reduceClipRegion (const Image& image, const Rectangle& sourceClipRegion, - const AffineTransform& transform) throw(); + AffineTransform transform; - /** Excludes a rectangle to stop it being drawn into. */ - void excludeClipRegion (const int x, const int y, - const int width, const int height) throw(); + juce_UseDebuggingNewOperator +}; - /** Returns true if no drawing can be done because the clip region is zero. */ - bool isClipEmpty() const throw(); +#endif // __JUCE_FILLTYPE_JUCEHEADER__ +/********* End of inlined file: juce_FillType.h *********/ - /** Saves the current graphics state on an internal stack. +/********* Start of inlined file: juce_RectanglePlacement.h *********/ +#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ +#define __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ - To restore the state, use restoreState(). - */ - void saveState() throw(); +/** + Defines the method used to postion some kind of rectangular object within + a rectangular viewport. - /** Restores a graphics state that was previously saved with saveState(). - */ - void restoreState() throw(); + Although similar to Justification, this is more specific, and has some extra + options. +*/ +class JUCE_API RectanglePlacement +{ +public: - /** Moves the position of the context's origin. + /** Creates a RectanglePlacement object using a combination of flags. */ + inline RectanglePlacement (const int flags_) throw() : flags (flags_) {} - This changes the position that the context considers to be (0, 0) to - the specified position. + /** Creates a copy of another Justification object. */ + RectanglePlacement (const RectanglePlacement& other) throw(); - So if you call setOrigin (100, 100), then the position that was previously - referred to as (100, 100) will subsequently be considered to be (0, 0). + /** Copies another Justification object. */ + const RectanglePlacement& operator= (const RectanglePlacement& other) throw(); - @see reduceClipRegion - */ - void setOrigin (const int newOriginX, - const int newOriginY) throw(); + /** Flag values that can be combined and used in the constructor. */ + enum + { - /** Resets the current colour, brush, and font to default settings. */ - void resetToDefaultState() throw(); + /** Indicates that the source rectangle's left edge should be aligned with the left edge of the target rectangle. */ + xLeft = 1, - /** Returns true if this context is drawing to a vector-based device, such as a printer. */ - bool isVectorDevice() const throw(); + /** Indicates that the source rectangle's right edge should be aligned with the right edge of the target rectangle. */ + xRight = 2, - juce_UseDebuggingNewOperator + /** Indicates that the source should be placed in the centre between the left and right + sides of the available space. */ + xMid = 4, - /** Create a graphics that uses a given low-level renderer. + /** Indicates that the source's top edge should be aligned with the top edge of the + destination rectangle. */ + yTop = 8, - For internal use only. + /** Indicates that the source's bottom edge should be aligned with the bottom edge of the + destination rectangle. */ + yBottom = 16, - NB. The context will NOT be deleted by this object when it is deleted. - */ - Graphics (LowLevelGraphicsContext* const internalContext) throw(); + /** Indicates that the source should be placed in the centre between the top and bottom + sides of the available space. */ + yMid = 32, - /** @internal */ - LowLevelGraphicsContext* getInternalContext() const throw() { return context; } + /** If this flag is set, then the source rectangle will be resized to completely fill + the destination rectangle, and all other flags are ignored. + */ + stretchToFit = 64, -private: + /** If this flag is set, then the source rectangle will be resized so that it is the + minimum size to completely fill the destination rectangle, without changing its + aspect ratio. This means that some of the source rectangle may fall outside + the destination. - LowLevelGraphicsContext* const context; - const bool ownsContext; + If this flag is not set, the source will be given the maximum size at which none + of it falls outside the destination rectangle. + */ + fillDestination = 128, - bool saveStatePending; - void saveStateIfPending() throw(); + /** Indicates that the source rectangle can be reduced in size if required, but should + never be made larger than its original size. + */ + onlyReduceInSize = 256, - const Graphics& operator= (const Graphics& other); - Graphics (const Graphics&); -}; + /** Indicates that the source rectangle can be enlarged if required, but should + never be made smaller than its original size. + */ + onlyIncreaseInSize = 512, -#endif // __JUCE_GRAPHICS_JUCEHEADER__ -/********* End of inlined file: juce_Graphics.h *********/ + /** Indicates that the source rectangle's size should be left unchanged. + */ + doNotResize = (onlyIncreaseInSize | onlyReduceInSize), -/** - A graphical effect filter that can be applied to components. + /** A shorthand value that is equivalent to (xMid | yMid). */ + centred = 4 + 32 + }; - An ImageEffectFilter can be applied to the image that a component - paints before it hits the screen. + /** Returns the raw flags that are set for this object. */ + inline int getFlags() const throw() { return flags; } - This is used for adding effects like shadows, blurs, etc. + /** Tests a set of flags for this object. - @see Component::setComponentEffect -*/ -class JUCE_API ImageEffectFilter -{ -public: + @returns true if any of the flags passed in are set on this object. + */ + inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } - /** Overridden to render the effect. + /** Adjusts the position and size of a rectangle to fit it into a space. - The implementation of this method must use the image that is passed in - as its source, and should render its output to the graphics context passed in. + The source rectangle co-ordinates will be adjusted so that they fit into + the destination rectangle based on this object's flags. + */ + void applyTo (double& sourceX, + double& sourceY, + double& sourceW, + double& sourceH, + const double destinationX, + const double destinationY, + const double destinationW, + const double destinationH) const throw(); - @param sourceImage the image that the source component has just rendered with - its paint() method. The image may or may not have an alpha - channel, depending on whether the component is opaque. - @param destContext the graphics context to use to draw the resultant image. + /** Returns the transform that should be applied to these source co-ordinates to fit them + into the destination rectangle using the current flags. */ - virtual void applyEffect (Image& sourceImage, - Graphics& destContext) = 0; + const AffineTransform getTransformToFit (float sourceX, + float sourceY, + float sourceW, + float sourceH, + const float destinationX, + const float destinationY, + const float destinationW, + const float destinationH) const throw(); - /** Destructor. */ - virtual ~ImageEffectFilter() {} +private: + int flags; }; -#endif // __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ -/********* End of inlined file: juce_ImageEffectFilter.h *********/ +#endif // __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ +/********* End of inlined file: juce_RectanglePlacement.h *********/ -/********* Start of inlined file: juce_RectangleList.h *********/ -#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ -#define __JUCE_RECTANGLELIST_JUCEHEADER__ +class LowLevelGraphicsContext; +class Image; +class RectangleList; /** - Maintains a set of rectangles as a complex region. + A graphics context, used for drawing a component or image. - This class allows a set of rectangles to be treated as a solid shape, and can - add and remove rectangular sections of it, and simplify overlapping or - adjacent rectangles. + When a Component needs painting, a Graphics context is passed to its + Component::paint() method, and this you then call methods within this + object to actually draw the component's content. - @see Rectangle + A Graphics can also be created from an image, to allow drawing directly onto + that image. + + @see Component::paint */ -class JUCE_API RectangleList +class JUCE_API Graphics { public: - /** Creates an empty RectangleList */ - RectangleList() throw(); - - /** Creates a copy of another list */ - RectangleList (const RectangleList& other) throw(); + /** Creates a Graphics object to draw directly onto the given image. - /** Creates a list containing just one rectangle. */ - RectangleList (const Rectangle& rect) throw(); + The graphics object that is created will be set up to draw onto the image, + with the context's clipping area being the entire size of the image, and its + origin being the image's origin. To draw into a subsection of an image, use the + reduceClipRegion() and setOrigin() methods. - /** Copies this list from another one. */ - const RectangleList& operator= (const RectangleList& other) throw(); + Obviously you shouldn't delete the image before this context is deleted. + */ + Graphics (Image& imageToDrawOnto) throw(); /** Destructor. */ - ~RectangleList() throw(); + ~Graphics() throw(); - /** Returns true if the region is empty. */ - bool isEmpty() const throw(); + /** Changes the current drawing colour. - /** Returns the number of rectangles in the list. */ - int getNumRectangles() const throw() { return rects.size(); } + This sets the colour that will now be used for drawing operations - it also + sets the opacity to that of the colour passed-in. - /** Returns one of the rectangles at a particular index. + If a brush is being used when this method is called, the brush will be deselected, + and any subsequent drawing will be done with a solid colour brush instead. - @returns the rectangle at the index, or an empty rectangle if the - index is out-of-range. + @see setOpacity */ - const Rectangle getRectangle (const int index) const throw(); - - /** Removes all rectangles to leave an empty region. */ - void clear() throw(); + void setColour (const Colour& newColour) throw(); - /** Merges a new rectangle into the list. + /** Changes the opacity to use with the current colour. - The rectangle being added will first be clipped to remove any parts of it - that overlap existing rectangles in the list. - */ - void add (const int x, const int y, - const int w, const int h) throw(); + If a solid colour is being used for drawing, this changes its opacity + to this new value (i.e. it doesn't multiply the colour's opacity by this amount). - /** Merges a new rectangle into the list. + If a gradient is being used, this will have no effect on it. - The rectangle being added will first be clipped to remove any parts of it - that overlap existing rectangles in the list, and adjacent rectangles will be - merged into it. + A value of 0.0 is completely transparent, 1.0 is completely opaque. */ - void add (const Rectangle& rect) throw(); - - /** Dumbly adds a rectangle to the list without checking for overlaps. + void setOpacity (const float newOpacity) throw(); - This simply adds the rectangle to the end, it doesn't merge it or remove - any overlapping bits. + /** Sets the context to use a gradient for its fill pattern. */ - void addWithoutMerging (const Rectangle& rect) throw(); - - /** Merges another rectangle list into this one. + void setGradientFill (const ColourGradient& gradient) throw(); - Any overlaps between the two lists will be clipped, so that the result is - the union of both lists. + /** Sets the context to use a tiled image pattern for filling. + Make sure that you don't delete this image while it's still being used by + this context! */ - void add (const RectangleList& other) throw(); - - /** Removes a rectangular region from the list. + void setTiledImageFill (const Image& imageToUse, + const int anchorX, + const int anchorY, + const float opacity) throw(); - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. + /** Changes the current fill settings. + @see setColour, setGradientFill, setTiledImageFill */ - void subtract (const Rectangle& rect) throw(); + void setFillType (const FillType& newFill) throw(); - /** Removes all areas in another RectangleList from this one. + /** Changes the font to use for subsequent text-drawing functions. - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. - */ - void subtract (const RectangleList& otherList) throw(); + Note there's also a setFont (float, int) method to quickly change the size and + style of the current font. - /** Removes any areas of the region that lie outside a given rectangle. + @see drawSingleLineText, drawMultiLineText, drawTextAsPath, drawText, drawFittedText + */ + void setFont (const Font& newFont) throw(); - Any rectangles in the list which overlap this will be clipped and subdivided - if necessary. + /** Changes the size and style of the currently-selected font. - Returns true if the resulting region is not empty, false if it is empty. + This is a convenient shortcut that changes the context's current font to a + different size or style. The typeface won't be changed. - @see getIntersectionWith + @see Font */ - bool clipTo (const Rectangle& rect) throw(); - - /** Removes any areas of the region that lie outside a given rectangle list. + void setFont (const float newFontHeight, + const int fontStyleFlags = Font::plain) throw(); - Any rectangles in this object which overlap the specified list will be clipped - and subdivided if necessary. + /** Draws a one-line text string. - Returns true if the resulting region is not empty, false if it is empty. + This will use the current colour (or brush) to fill the text. The font is the last + one specified by setFont(). - @see getIntersectionWith + @param text the string to draw + @param startX the position to draw the left-hand edge of the text + @param baselineY the position of the text's baseline + @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText */ - bool clipTo (const RectangleList& other) throw(); - - /** Creates a region which is the result of clipping this one to a given rectangle. + void drawSingleLineText (const String& text, + const int startX, + const int baselineY) const throw(); - Unlike the other clipTo method, this one doesn't affect this object - it puts the - resulting region into the list whose reference is passed-in. + /** Draws text across multiple lines. - Returns true if the resulting region is not empty, false if it is empty. + This will break the text onto a new line where there's a new-line or + carriage-return character, or at a word-boundary when the text becomes wider + than the size specified by the maximumLineWidth parameter. - @see clipTo + @see setFont, drawSingleLineText, drawFittedText, GlyphArrangement::addJustifiedText */ - bool getIntersectionWith (const Rectangle& rect, RectangleList& destRegion) const throw(); - - /** Swaps the contents of this and another list. + void drawMultiLineText (const String& text, + const int startX, + const int baselineY, + const int maximumLineWidth) const throw(); - This swaps their internal pointers, so is hugely faster than using copy-by-value - to swap them. - */ - void swapWith (RectangleList& otherList) throw(); + /** Renders a string of text as a vector path. - /** Checks whether the region contains a given point. + This allows a string to be transformed with an arbitrary AffineTransform and + rendered using the current colour/brush. It's much slower than the normal text methods + but more accurate. - @returns true if the point lies within one of the rectangles in the list + @see setFont */ - bool containsPoint (const int x, const int y) const throw(); + void drawTextAsPath (const String& text, + const AffineTransform& transform) const throw(); - /** Checks whether the region contains the whole of a given rectangle. + /** Draws a line of text within a specified rectangle. - @returns true all parts of the rectangle passed in lie within the region - defined by this object - @see intersectsRectangle, containsPoint + The text will be positioned within the rectangle based on the justification + flags passed-in. If the string is too long to fit inside the rectangle, it will + either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig + flag is true). + + @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText */ - bool containsRectangle (const Rectangle& rectangleToCheck) const throw(); + void drawText (const String& text, + const int x, + const int y, + const int width, + const int height, + const Justification& justificationType, + const bool useEllipsesIfTooBig) const throw(); - /** Checks whether the region contains any part of a given rectangle. + /** Tries to draw a text string inside a given space. - @returns true if any part of the rectangle passed in lies within the region - defined by this object - @see containsRectangle - */ - bool intersectsRectangle (const Rectangle& rectangleToCheck) const throw(); - - /** Checks whether this region intersects any part of another one. + This does its best to make the given text readable within the specified rectangle, + so it useful for labelling things. - @see intersectsRectangle - */ - bool intersects (const RectangleList& other) const throw(); + If the text is too big, it'll be squashed horizontally or broken over multiple lines + if the maximumLinesToUse value allows this. If the text just won't fit into the space, + it'll cram as much as possible in there, and put some ellipsis at the end to show that + it's been truncated. - /** Returns the smallest rectangle that can enclose the whole of this region. */ - const Rectangle getBounds() const throw(); + A Justification parameter lets you specify how the text is laid out within the rectangle, + both horizontally and vertically. - /** Optimises the list into a minimum number of constituent rectangles. + The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally + to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you + can set this value to 1.0f. - This will try to combine any adjacent rectangles into larger ones where - possible, to simplify lists that might have been fragmented by repeated - add/subtract calls. + @see GlyphArrangement::addFittedText */ - void consolidate() throw(); - - /** Adds an x and y value to all the co-ordinates. */ - void offsetAll (const int dx, const int dy) throw(); - - /** Creates a Path object to represent this region. */ - const Path toPath() const throw(); + void drawFittedText (const String& text, + const int x, + const int y, + const int width, + const int height, + const Justification& justificationFlags, + const int maximumNumberOfLines, + const float minimumHorizontalScale = 0.7f) const throw(); - /** An iterator for accessing all the rectangles in a RectangleList. */ - class Iterator - { - public: + /** Fills the context's entire clip region with the current colour or brush. - Iterator (const RectangleList& list) throw(); - ~Iterator() throw(); + (See also the fillAll (const Colour&) method which is a quick way of filling + it with a given colour). + */ + void fillAll() const throw(); - /** Advances to the next rectangle, and returns true if it's not finished. + /** Fills the context's entire clip region with a given colour. - Call this before using getRectangle() to find the rectangle that was returned. - */ - bool next() throw(); + This leaves the context's current colour and brush unchanged, it just + uses the specified colour temporarily. + */ + void fillAll (const Colour& colourToUse) const throw(); - /** Returns the current rectangle. */ - const Rectangle* getRectangle() const throw() { return current; } + /** Fills a rectangle with the current colour or brush. - juce_UseDebuggingNewOperator + @see drawRect, fillRoundedRectangle + */ + void fillRect (int x, + int y, + int width, + int height) const throw(); - private: - const Rectangle* current; - const RectangleList& owner; - int index; + /** Fills a rectangle with the current colour or brush. */ + void fillRect (const Rectangle& rectangle) const throw(); - Iterator (const Iterator&); - const Iterator& operator= (const Iterator&); - }; + /** Fills a rectangle with the current colour or brush. - juce_UseDebuggingNewOperator + This uses sub-pixel positioning so is slower than the fillRect method which + takes integer co-ordinates. + */ + void fillRect (const float x, + const float y, + const float width, + const float height) const throw(); -private: - friend class Iterator; - Array rects; -}; + /** Uses the current colour or brush to fill a rectangle with rounded corners. -#endif // __JUCE_RECTANGLELIST_JUCEHEADER__ -/********* End of inlined file: juce_RectangleList.h *********/ + @see drawRoundedRectangle, Path::addRoundedRectangle + */ + void fillRoundedRectangle (const float x, + const float y, + const float width, + const float height, + const float cornerSize) const throw(); -/********* Start of inlined file: juce_BorderSize.h *********/ -#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ -#define __JUCE_BORDERSIZE_JUCEHEADER__ + /** Uses the current colour or brush to fill a rectangle with rounded corners. -/** - Specifies a set of gaps to be left around the sides of a rectangle. + @see drawRoundedRectangle, Path::addRoundedRectangle + */ + void fillRoundedRectangle (const Rectangle& rectangle, + const float cornerSize) const throw(); - This is basically the size of the spaces at the top, bottom, left and right of - a rectangle. It's used by various component classes to specify borders. + /** Fills a rectangle with a checkerboard pattern, alternating between two colours. + */ + void fillCheckerBoard (int x, int y, + int width, int height, + const int checkWidth, + const int checkHeight, + const Colour& colour1, + const Colour& colour2) const throw(); - @see Rectangle -*/ -class JUCE_API BorderSize -{ -public: + /** Draws four lines to form a rectangular outline, using the current colour or brush. - /** Creates a null border. + The lines are drawn inside the given rectangle, and greater line thicknesses + extend inwards. - All sizes are left as 0. + @see fillRect */ - BorderSize() throw(); + void drawRect (const int x, + const int y, + const int width, + const int height, + const int lineThickness = 1) const throw(); - /** Creates a copy of another border. */ - BorderSize (const BorderSize& other) throw(); + /** Draws four lines to form a rectangular outline, using the current colour or brush. - /** Creates a border with the given gaps. */ - BorderSize (const int topGap, - const int leftGap, - const int bottomGap, - const int rightGap) throw(); + The lines are drawn inside the given rectangle, and greater line thicknesses + extend inwards. - /** Creates a border with the given gap on all sides. */ - BorderSize (const int allGaps) throw(); + @see fillRect + */ + void drawRect (const float x, + const float y, + const float width, + const float height, + const float lineThickness = 1.0f) const throw(); - /** Destructor. */ - ~BorderSize() throw(); + /** Draws four lines to form a rectangular outline, using the current colour or brush. - /** Returns the gap that should be left at the top of the region. */ - int getTop() const throw() { return top; } + The lines are drawn inside the given rectangle, and greater line thicknesses + extend inwards. - /** Returns the gap that should be left at the top of the region. */ - int getLeft() const throw() { return left; } + @see fillRect + */ + void drawRect (const Rectangle& rectangle, + const int lineThickness = 1) const throw(); - /** Returns the gap that should be left at the top of the region. */ - int getBottom() const throw() { return bottom; } + /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. - /** Returns the gap that should be left at the top of the region. */ - int getRight() const throw() { return right; } + @see fillRoundedRectangle, Path::addRoundedRectangle + */ + void drawRoundedRectangle (const float x, + const float y, + const float width, + const float height, + const float cornerSize, + const float lineThickness) const throw(); - /** Returns the sum of the top and bottom gaps. */ - int getTopAndBottom() const throw() { return top + bottom; } + /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. - /** Returns the sum of the left and right gaps. */ - int getLeftAndRight() const throw() { return left + right; } + @see fillRoundedRectangle, Path::addRoundedRectangle + */ + void drawRoundedRectangle (const Rectangle& rectangle, + const float cornerSize, + const float lineThickness) const throw(); - /** Changes the top gap. */ - void setTop (const int newTopGap) throw(); + /** Draws a 3D raised (or indented) bevel using two colours. - /** Changes the left gap. */ - void setLeft (const int newLeftGap) throw(); + The bevel is drawn inside the given rectangle, and greater bevel thicknesses + extend inwards. - /** Changes the bottom gap. */ - void setBottom (const int newBottomGap) throw(); + The top-left colour is used for the top- and left-hand edges of the + bevel; the bottom-right colour is used for the bottom- and right-hand + edges. - /** Changes the right gap. */ - void setRight (const int newRightGap) throw(); + If useGradient is true, then the bevel fades out to make it look more curved + and less angular. If sharpEdgeOnOutside is true, the outside of the bevel is + sharp, and it fades towards the centre; if sharpEdgeOnOutside is false, then + the centre edges are sharp and it fades towards the outside. + */ + void drawBevel (const int x, + const int y, + const int width, + const int height, + const int bevelThickness, + const Colour& topLeftColour = Colours::white, + const Colour& bottomRightColour = Colours::black, + const bool useGradient = true, + const bool sharpEdgeOnOutside = true) const throw(); - /** Returns a rectangle with these borders removed from it. */ - const Rectangle subtractedFrom (const Rectangle& original) const throw(); + /** Draws a pixel using the current colour or brush. + */ + void setPixel (int x, int y) const throw(); - /** Removes this border from a given rectangle. */ - void subtractFrom (Rectangle& rectangle) const throw(); + /** Fills an ellipse with the current colour or brush. - /** Returns a rectangle with these borders added around it. */ - const Rectangle addedTo (const Rectangle& original) const throw(); + The ellipse is drawn to fit inside the given rectangle. - /** Adds this border around a given rectangle. */ - void addTo (Rectangle& original) const throw(); + @see drawEllipse, Path::addEllipse + */ + void fillEllipse (const float x, + const float y, + const float width, + const float height) const throw(); - bool operator== (const BorderSize& other) const throw(); - bool operator!= (const BorderSize& other) const throw(); + /** Draws an elliptical stroke using the current colour or brush. - juce_UseDebuggingNewOperator + @see fillEllipse, Path::addEllipse + */ + void drawEllipse (const float x, + const float y, + const float width, + const float height, + const float lineThickness) const throw(); -private: - int top, left, bottom, right; -}; + /** Draws a line between two points. -#endif // __JUCE_BORDERSIZE_JUCEHEADER__ -/********* End of inlined file: juce_BorderSize.h *********/ + The line is 1 pixel wide and drawn with the current colour or brush. + */ + void drawLine (float startX, + float startY, + float endX, + float endY) const throw(); -/********* Start of inlined file: juce_ComponentPeer.h *********/ -#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ -#define __JUCE_COMPONENTPEER_JUCEHEADER__ + /** Draws a line between two points with a given thickness. -class Component; -class Graphics; + @see Path::addLineSegment + */ + void drawLine (const float startX, + const float startY, + const float endX, + const float endY, + const float lineThickness) const throw(); -class ComponentBoundsConstrainer; -class ComponentDeletionWatcher; + /** Draws a line between two points. -/** - The base class for window objects that wrap a component as a real operating - system object. + The line is 1 pixel wide and drawn with the current colour or brush. + */ + void drawLine (const Line& line) const throw(); - This is an abstract base class - the platform specific code contains default - implementations of it that create and manage windows. + /** Draws a line between two points with a given thickness. - @see Component::createNewPeer -*/ -class JUCE_API ComponentPeer : public MessageListener -{ -public: + @see Path::addLineSegment + */ + void drawLine (const Line& line, + const float lineThickness) const throw(); - /** A combination of these flags is passed to the ComponentPeer constructor. */ - enum StyleFlags - { - windowAppearsOnTaskbar = (1 << 0), /**< Indicates that the window should have a corresponding - entry on the taskbar (ignored on MacOSX) */ - windowIsTemporary = (1 << 1), /**< Indicates that the window is a temporary popup, like a menu, - tooltip, etc. */ - windowIgnoresMouseClicks = (1 << 2), /**< Indicates that the window should let mouse clicks pass - through it (may not be possible on some platforms). */ - windowHasTitleBar = (1 << 3), /**< Indicates that the window should have a normal OS-specific - title bar and frame\. if not specified, the window will be - borderless. */ - windowIsResizable = (1 << 4), /**< Indicates that the window should have a resizable border. */ - windowHasMinimiseButton = (1 << 5), /**< Indicates that if the window has a title bar, it should have a - minimise button on it. */ - windowHasMaximiseButton = (1 << 6), /**< Indicates that if the window has a title bar, it should have a - maximise button on it. */ - windowHasCloseButton = (1 << 7), /**< Indicates that if the window has a title bar, it should have a - close button on it. */ - windowHasDropShadow = (1 << 8), /**< Indicates that the window should have a drop-shadow (this may - not be possible on all platforms). */ - windowRepaintedExplictly = (1 << 9), /**< Not intended for public use - this tells a window not to - do its own repainting, but only to repaint when the - performAnyPendingRepaintsNow() method is called. */ - windowIgnoresKeyPresses = (1 << 10), /**< Tells the window not to catch any keypresses. This can - be used for things like plugin windows, to stop them interfering - with the host's shortcut keys */ - windowIsSemiTransparent = (1 << 31) /**< Not intended for public use - makes a window transparent. */ + /** Draws a dashed line using a custom set of dash-lengths. - }; + @param startX the line's start x co-ordinate + @param startY the line's start y co-ordinate + @param endX the line's end x co-ordinate + @param endY the line's end y co-ordinate + @param dashLengths a series of lengths to specify the on/off lengths - e.g. + { 4, 5, 6, 7 } will draw a line of 4 pixels, skip 5 pixels, + draw 6 pixels, skip 7 pixels, and then repeat. + @param numDashLengths the number of elements in the array (this must be an even number). + @param lineThickness the thickness of the line to draw + @see PathStrokeType::createDashedStroke + */ + void drawDashedLine (const float startX, + const float startY, + const float endX, + const float endY, + const float* const dashLengths, + const int numDashLengths, + const float lineThickness = 1.0f) const throw(); - /** Creates a peer. + /** Draws a vertical line of pixels at a given x position. - The component is the one that we intend to represent, and the style flags are - a combination of the values in the StyleFlags enum + The x position is an integer, but the top and bottom of the line can be sub-pixel + positions, and these will be anti-aliased if necessary. */ - ComponentPeer (Component* const component, - const int styleFlags) throw(); + void drawVerticalLine (const int x, float top, float bottom) const throw(); - /** Destructor. */ - virtual ~ComponentPeer(); + /** Draws a horizontal line of pixels at a given y position. - /** Returns the component being represented by this peer. */ - Component* getComponent() const throw() { return component; } + The y position is an integer, but the left and right ends of the line can be sub-pixel + positions, and these will be anti-aliased if necessary. + */ + void drawHorizontalLine (const int y, float left, float right) const throw(); - /** Returns the set of style flags that were set when the window was created. + /** Fills a path using the currently selected colour or brush. + */ + void fillPath (const Path& path, + const AffineTransform& transform = AffineTransform::identity) const throw(); - @see Component::addToDesktop + /** Draws a path's outline using the currently selected colour or brush. */ - int getStyleFlags() const throw() { return styleFlags; } + void strokePath (const Path& path, + const PathStrokeType& strokeType, + const AffineTransform& transform = AffineTransform::identity) const throw(); - /** Returns the raw handle to whatever kind of window is being used. + /** Draws a line with an arrowhead. - On windows, this is probably a HWND, on the mac, it's likely to be a WindowRef, - but rememeber there's no guarantees what you'll get back. + @param startX the line's start x co-ordinate + @param startY the line's start y co-ordinate + @param endX the line's end x co-ordinate (the tip of the arrowhead) + @param endY the line's end y co-ordinate (the tip of the arrowhead) + @param lineThickness the thickness of the line + @param arrowheadWidth the width of the arrow head (perpendicular to the line) + @param arrowheadLength the length of the arrow head (along the length of the line) */ - virtual void* getNativeHandle() const = 0; + void drawArrow (const float startX, + const float startY, + const float endX, + const float endY, + const float lineThickness, + const float arrowheadWidth, + const float arrowheadLength) const throw(); - /** Shows or hides the window. */ - virtual void setVisible (bool shouldBeVisible) = 0; + /** Types of rendering quality that can be specified when drawing images. - /** Changes the title of the window. */ - virtual void setTitle (const String& title) = 0; + @see blendImage, Graphics::setImageResamplingQuality + */ + enum ResamplingQuality + { + lowResamplingQuality = 0, /**< Just uses a nearest-neighbour algorithm for resampling. */ + mediumResamplingQuality = 1, /**< Uses bilinear interpolation for upsampling and area-averaging for downsampling. */ + highResamplingQuality = 2 /**< Uses bicubic interpolation for upsampling and area-averaging for downsampling. */ + }; - /** Moves the window without changing its size. + /** Changes the quality that will be used when resampling images. - If the native window is contained in another window, then the co-ordinates are - relative to the parent window's origin, not the screen origin. + By default a Graphics object will be set to mediumRenderingQuality. - This should result in a callback to handleMovedOrResized(). + @see Graphics::drawImage, Graphics::drawImageTransformed, Graphics::drawImageWithin */ - virtual void setPosition (int x, int y) = 0; + void setImageResamplingQuality (const ResamplingQuality newQuality) throw(); - /** Resizes the window without changing its position. + /** Draws an image. - This should result in a callback to handleMovedOrResized(). - */ - virtual void setSize (int w, int h) = 0; + This will draw the whole of an image, positioning its top-left corner at the + given co-ordinates, and keeping its size the same. This is the simplest image + drawing method - the others give more control over the scaling and clipping + of the images. - /** Moves and resizes the window. + Images are composited using the context's current opacity, so if you + don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) + (or setColour() with an opaque colour) before drawing images. + */ + void drawImageAt (const Image* const imageToDraw, + const int topLeftX, + const int topLeftY, + const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - If the native window is contained in another window, then the co-ordinates are - relative to the parent window's origin, not the screen origin. + /** Draws part of an image, rescaling it to fit in a given target region. - This should result in a callback to handleMovedOrResized(). - */ - virtual void setBounds (int x, int y, int w, int h, const bool isNowFullScreen) = 0; + The specified area of the source image is rescaled and drawn to fill the + specifed destination rectangle. - /** Returns the current position and size of the window. + Images are composited using the context's current opacity, so if you + don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) + (or setColour() with an opaque colour) before drawing images. - If the native window is contained in another window, then the co-ordinates are - relative to the parent window's origin, not the screen origin. + @param imageToDraw the image to overlay + @param destX the left of the destination rectangle + @param destY the top of the destination rectangle + @param destWidth the width of the destination rectangle + @param destHeight the height of the destination rectangle + @param sourceX the left of the rectangle to copy from the source image + @param sourceY the top of the rectangle to copy from the source image + @param sourceWidth the width of the rectangle to copy from the source image + @param sourceHeight the height of the rectangle to copy from the source image + @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the source image's pixels, + the source image's alpha channel is used as a mask with + which to fill the destination using the current colour + or brush. (If the source is has no alpha channel, then + it will just fill the target with a solid rectangle) + @see setImageResamplingQuality, drawImageAt, drawImageWithin, fillAlphaMap */ - virtual void getBounds (int& x, int& y, int& w, int& h) const = 0; + void drawImage (const Image* const imageToDraw, + int destX, + int destY, + int destWidth, + int destHeight, + int sourceX, + int sourceY, + int sourceWidth, + int sourceHeight, + const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - /** Returns the x-position of this window, relative to the screen's origin. */ - virtual int getScreenX() const = 0; + /** Draws part of an image, having applied an affine transform to it. - /** Returns the y-position of this window, relative to the screen's origin. */ - virtual int getScreenY() const = 0; + This lets you throw the image around in some wacky ways, rotate it, shear, + scale it, etc. - /** Converts a position relative to the top-left of this component to screen co-ordinates. */ - virtual void relativePositionToGlobal (int& x, int& y) = 0; + A subregion is specified within the source image, and all transformations + will be treated as relative to the origin of this sub-region. So, for example if + your subregion is (50, 50, 100, 100), and your transform is a translation of (20, 20), + the resulting pixel drawn at (20, 20) in the destination context is from (50, 50) in + your image. If you want to use the whole image, then Image::getBounds() returns a + suitable rectangle to use as the imageSubRegion parameter. - /** Converts a screen co-ordinate to a position relative to the top-left of this component. */ - virtual void globalPositionToRelative (int& x, int& y) = 0; + Images are composited using the context's current opacity, so if you + don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) + (or setColour() with an opaque colour) before drawing images. - /** Minimises the window. */ - virtual void setMinimised (bool shouldBeMinimised) = 0; + If fillAlphaChannelWithCurrentBrush is set to true, then the image's RGB channels + are ignored and it is filled with the current brush, masked by its alpha channel. - /** True if the window is currently minimised. */ - virtual bool isMinimised() const = 0; + @see setImageResamplingQuality, drawImage + */ + void drawImageTransformed (const Image* const imageToDraw, + const Rectangle& imageSubRegion, + const AffineTransform& transform, + const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - /** Enable/disable fullscreen mode for the window. */ - virtual void setFullScreen (bool shouldBeFullScreen) = 0; + /** Draws an image to fit within a designated rectangle. - /** True if the window is currently full-screen. */ - virtual bool isFullScreen() const = 0; - - /** Sets the size to restore to if fullscreen mode is turned off. */ - void setNonFullScreenBounds (const Rectangle& newBounds) throw(); - - /** Returns the size to restore to if fullscreen mode is turned off. */ - const Rectangle& getNonFullScreenBounds() const throw(); - - /** Attempts to change the icon associated with this window. - */ - virtual void setIcon (const Image& newIcon) = 0; - - /** Sets a constrainer to use if the peer can resize itself. - - The constrainer won't be deleted by this object, so the caller must manage its lifetime. - */ - void setConstrainer (ComponentBoundsConstrainer* const newConstrainer) throw(); - - /** Returns the current constrainer, if one has been set. */ - ComponentBoundsConstrainer* getConstrainer() const throw() { return constrainer; } - - /** Checks if a point is in the window. + If the image is too big or too small for the space, it will be rescaled + to fit as nicely as it can do without affecting its aspect ratio. It will + then be placed within the target rectangle according to the justification flags + specified. - Coordinates are relative to the top-left of this window. If trueIfInAChildWindow - is false, then this returns false if the point is actually inside a child of this - window. + @param imageToDraw the source image to draw + @param destX top-left of the target rectangle to fit it into + @param destY top-left of the target rectangle to fit it into + @param destWidth size of the target rectangle to fit the image into + @param destHeight size of the target rectangle to fit the image into + @param placementWithinTarget this specifies how the image should be positioned + within the target rectangle - see the RectanglePlacement + class for more details about this. + @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the image, just its + alpha channel will be used as a mask with which to + draw with the current brush or colour. This is + similar to fillAlphaMap(), and see also drawImage() + @see setImageResamplingQuality, drawImage, drawImageTransformed, drawImageAt, RectanglePlacement */ - virtual bool contains (int x, int y, bool trueIfInAChildWindow) const = 0; + void drawImageWithin (const Image* const imageToDraw, + const int destX, + const int destY, + const int destWidth, + const int destHeight, + const RectanglePlacement& placementWithinTarget, + const bool fillAlphaChannelWithCurrentBrush = false) const throw(); - /** Returns the size of the window frame that's around this window. + /** Returns the position of the bounding box for the current clipping region. - Whether or not the window has a normal window frame depends on the flags - that were set when the window was created by Component::addToDesktop() + @see getClipRegion, clipRegionIntersects */ - virtual const BorderSize getFrameSize() const = 0; + const Rectangle getClipBounds() const throw(); - /** This is called when the window's bounds change. + /** Checks whether a rectangle overlaps the context's clipping region. - A peer implementation must call this when the window is moved and resized, so that - this method can pass the message on to the component. + If this returns false, no part of the given area can be drawn onto, so this + method can be used to optimise a component's paint() method, by letting it + avoid drawing complex objects that aren't within the region being repainted. */ - void handleMovedOrResized(); + bool clipRegionIntersects (const int x, const int y, const int width, const int height) const throw(); - /** This is called if the screen resolution changes. + /** Intersects the current clipping region with another region. - A peer implementation must call this if the monitor arrangement changes or the available - screen size changes. + @returns true if the resulting clipping region is non-zero in size + @see setOrigin, clipRegionIntersects */ - void handleScreenSizeChange(); - - /** This is called to repaint the component into the given context. */ - void handlePaint (LowLevelGraphicsContext& contextToPaintTo); + bool reduceClipRegion (const int x, const int y, + const int width, const int height) throw(); - /** Sets this window to either be always-on-top or normal. + /** Intersects the current clipping region with a rectangle list region. - Some kinds of window might not be able to do this, so should return false. + @returns true if the resulting clipping region is non-zero in size + @see setOrigin, clipRegionIntersects */ - virtual bool setAlwaysOnTop (bool alwaysOnTop) = 0; - - /** Brings the window to the top, optionally also giving it focus. */ - virtual void toFront (bool makeActive) = 0; + bool reduceClipRegion (const RectangleList& clipRegion) throw(); - /** Moves the window to be just behind another one. */ - virtual void toBehind (ComponentPeer* other) = 0; + /** Intersects the current clipping region with a path. - /** Called when the window is brought to the front, either by the OS or by a call - to toFront(). + @returns true if the resulting clipping region is non-zero in size + @see reduceClipRegion */ - void handleBroughtToFront(); - - /** True if the window has the keyboard focus. */ - virtual bool isFocused() const = 0; + bool reduceClipRegion (const Path& path, const AffineTransform& transform = AffineTransform::identity) throw(); - /** Tries to give the window keyboard focus. */ - virtual void grabFocus() = 0; + /** Intersects the current clipping region with an image's alpha-channel. - /** Tells the window that text input may be required at the given position. + The current clipping path is intersected with the area covered by this image's + alpha-channel, after the image has been transformed by the specified matrix. - This may cause things like a virtual on-screen keyboard to appear, depending - on the OS. + @param image the image whose alpha-channel should be used. If the image doesn't + have an alpha-channel, it is treated as entirely opaque. + @param sourceClipRegion a subsection of the image that should be used. To use the + entire image, just pass a rectangle of bounds + (0, 0, image.getWidth(), image.getHeight()). + @param transform a matrix to apply to the image + @returns true if the resulting clipping region is non-zero in size + @see reduceClipRegion */ - virtual void textInputRequired (int x, int y) = 0; + bool reduceClipRegion (const Image& image, const Rectangle& sourceClipRegion, + const AffineTransform& transform) throw(); - /** Called when the window gains keyboard focus. */ - void handleFocusGain(); - /** Called when the window loses keyboard focus. */ - void handleFocusLoss(); + /** Excludes a rectangle to stop it being drawn into. */ + void excludeClipRegion (const int x, const int y, + const int width, const int height) throw(); - Component* getLastFocusedSubcomponent() const throw(); + /** Returns true if no drawing can be done because the clip region is zero. */ + bool isClipEmpty() const throw(); - /** Called when a key is pressed. + /** Saves the current graphics state on an internal stack. - For keycode info, see the KeyPress class. - Returns true if the keystroke was used. + To restore the state, use restoreState(). */ - bool handleKeyPress (const int keyCode, - const juce_wchar textCharacter); + void saveState() throw(); - /** Called whenever a key is pressed or released. - Returns true if the keystroke was used. + /** Restores a graphics state that was previously saved with saveState(). */ - bool handleKeyUpOrDown (const bool isKeyDown); + void restoreState() throw(); - /** Called whenever a modifier key is pressed or released. */ - void handleModifierKeysChange(); + /** Moves the position of the context's origin. - /** Invalidates a region of the window to be repainted asynchronously. */ - virtual void repaint (int x, int y, int w, int h) = 0; + This changes the position that the context considers to be (0, 0) to + the specified position. - /** This can be called (from the message thread) to cause the immediate redrawing - of any areas of this window that need repainting. + So if you call setOrigin (100, 100), then the position that was previously + referred to as (100, 100) will subsequently be considered to be (0, 0). - You shouldn't ever really need to use this, it's mainly for special purposes - like supporting audio plugins where the host's event loop is out of our control. + @see reduceClipRegion */ - virtual void performAnyPendingRepaintsNow() = 0; - - void handleMouseEnter (int x, int y, const int64 time); - void handleMouseMove (int x, int y, const int64 time); - void handleMouseDown (int x, int y, const int64 time); - void handleMouseDrag (int x, int y, const int64 time); - void handleMouseUp (const int oldModifiers, int x, int y, const int64 time); - void handleMouseExit (int x, int y, const int64 time); - void handleMouseWheel (const int amountX, const int amountY, const int64 time); - - /** Causes a mouse-move callback to be made asynchronously. */ - void sendFakeMouseMove() throw(); - - void handleUserClosingWindow(); - - void handleFileDragMove (const StringArray& files, int x, int y); - void handleFileDragExit (const StringArray& files); - void handleFileDragDrop (const StringArray& files, int x, int y); - - /** Resets the masking region. - - The subclass should call this every time it's about to call the handlePaint - method. + void setOrigin (const int newOriginX, + const int newOriginY) throw(); - @see addMaskedRegion - */ - void clearMaskedRegion() throw(); + /** Resets the current colour, brush, and font to default settings. */ + void resetToDefaultState() throw(); - /** Adds a rectangle to the set of areas not to paint over. + /** Returns true if this context is drawing to a vector-based device, such as a printer. */ + bool isVectorDevice() const throw(); - A component can call this on its peer during its paint() method, to signal - that the painting code should ignore a given region. The reason - for this is to stop embedded windows (such as OpenGL) getting painted over. + juce_UseDebuggingNewOperator - The masked region is cleared each time before a paint happens, so a component - will have to make sure it calls this every time it's painted. - */ - void addMaskedRegion (int x, int y, int w, int h) throw(); + /** Create a graphics that uses a given low-level renderer. - /** Returns the number of currently-active peers. + For internal use only. - @see getPeer + NB. The context will NOT be deleted by this object when it is deleted. */ - static int getNumPeers() throw(); + Graphics (LowLevelGraphicsContext* const internalContext) throw(); - /** Returns one of the currently-active peers. + /** @internal */ + LowLevelGraphicsContext* getInternalContext() const throw() { return context; } - @see getNumPeers - */ - static ComponentPeer* getPeer (const int index) throw(); +private: - /** Checks if this peer object is valid. + LowLevelGraphicsContext* const context; + const bool ownsContext; - @see getNumPeers - */ - static bool isValidPeer (const ComponentPeer* const peer) throw(); + bool saveStatePending; + void saveStateIfPending() throw(); - static void bringModalComponentToFront(); + const Graphics& operator= (const Graphics& other); + Graphics (const Graphics&); +}; - virtual const StringArray getAvailableRenderingEngines() throw(); - virtual int getCurrentRenderingEngine() throw(); - virtual void setCurrentRenderingEngine (int index) throw(); +#endif // __JUCE_GRAPHICS_JUCEHEADER__ +/********* End of inlined file: juce_Graphics.h *********/ - juce_UseDebuggingNewOperator +/** + A graphical effect filter that can be applied to components. -protected: - Component* const component; - const int styleFlags; - RectangleList maskedRegion; - Rectangle lastNonFullscreenBounds; - uint32 lastPaintTime; - ComponentBoundsConstrainer* constrainer; + An ImageEffectFilter can be applied to the image that a component + paints before it hits the screen. - static void updateCurrentModifiers() throw(); + This is used for adding effects like shadows, blurs, etc. - /** @internal */ - void handleMessage (const Message& message); + @see Component::setComponentEffect +*/ +class JUCE_API ImageEffectFilter +{ +public: -private: + /** Overridden to render the effect. - Component* lastFocusedComponent; - ComponentDeletionWatcher* dragAndDropTargetComponent; - Component* lastDragAndDropCompUnderMouse; - bool fakeMouseMessageSent : 1, isWindowMinimised : 1; + The implementation of this method must use the image that is passed in + as its source, and should render its output to the graphics context passed in. - friend class Component; - static ComponentPeer* getPeerFor (const Component* const component) throw(); + @param sourceImage the image that the source component has just rendered with + its paint() method. The image may or may not have an alpha + channel, depending on whether the component is opaque. + @param destContext the graphics context to use to draw the resultant image. + */ + virtual void applyEffect (Image& sourceImage, + Graphics& destContext) = 0; - void setLastDragDropTarget (Component* comp); + /** Destructor. */ + virtual ~ImageEffectFilter() {} - ComponentPeer (const ComponentPeer&); - const ComponentPeer& operator= (const ComponentPeer&); }; -#endif // __JUCE_COMPONENTPEER_JUCEHEADER__ -/********* End of inlined file: juce_ComponentPeer.h *********/ +#endif // __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ +/********* End of inlined file: juce_ImageEffectFilter.h *********/ -class LookAndFeel; +/********* Start of inlined file: juce_RectangleList.h *********/ +#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ +#define __JUCE_RECTANGLELIST_JUCEHEADER__ /** - The base class for all JUCE user-interface objects. + Maintains a set of rectangles as a complex region. + + This class allows a set of rectangles to be treated as a solid shape, and can + add and remove rectangular sections of it, and simplify overlapping or + adjacent rectangles. + @see Rectangle */ -class JUCE_API Component : public MouseListener, - protected MessageListener +class JUCE_API RectangleList { public: - /** Creates a component. + /** Creates an empty RectangleList */ + RectangleList() throw(); - To get it to actually appear, you'll also need to: - - Either add it to a parent component or use the addToDesktop() method to - make it a desktop window - - Set its size and position to something sensible - - Use setVisible() to make it visible + /** Creates a copy of another list */ + RectangleList (const RectangleList& other) throw(); - And for it to serve any useful purpose, you'll need to write a - subclass of Component or use one of the other types of component from - the library. - */ - Component() throw(); + /** Creates a list containing just one rectangle. */ + RectangleList (const Rectangle& rect) throw(); - /** Destructor. + /** Copies this list from another one. */ + const RectangleList& operator= (const RectangleList& other) throw(); - Note that when a component is deleted, any child components it might - contain are NOT deleted unless you explicitly call deleteAllChildren() first. - */ - virtual ~Component(); + /** Destructor. */ + ~RectangleList() throw(); - /** Creates a component, setting its name at the same time. + /** Returns true if the region is empty. */ + bool isEmpty() const throw(); - @see getName, setName - */ - Component (const String& componentName) throw(); + /** Returns the number of rectangles in the list. */ + int getNumRectangles() const throw() { return rects.size(); } - /** Returns the name of this component. + /** Returns one of the rectangles at a particular index. - @see setName + @returns the rectangle at the index, or an empty rectangle if the + index is out-of-range. */ - const String& getName() const throw() { return componentName_; } + const Rectangle getRectangle (const int index) const throw(); - /** Sets the name of this component. + /** Removes all rectangles to leave an empty region. */ + void clear() throw(); - When the name changes, all registered ComponentListeners will receive a - ComponentListener::componentNameChanged() callback. + /** Merges a new rectangle into the list. - @see getName + The rectangle being added will first be clipped to remove any parts of it + that overlap existing rectangles in the list. */ - virtual void setName (const String& newName); - - /** Checks whether this Component object has been deleted. + void add (const int x, const int y, + const int w, const int h) throw(); - This will check whether this object is still a valid component, or whether - it's been deleted. + /** Merges a new rectangle into the list. - It's safe to call this on null or dangling pointers, but note that there is a - small risk if another new (but different) component has been created at the - same memory address which this one occupied, this methods can return a - false positive. + The rectangle being added will first be clipped to remove any parts of it + that overlap existing rectangles in the list, and adjacent rectangles will be + merged into it. */ - bool isValidComponent() const throw(); - - /** Makes the component visible or invisible. - - This method will show or hide the component. - Note that components default to being non-visible when first created. - Also note that visible components won't be seen unless all their parent components - are also visible. + void add (const Rectangle& rect) throw(); - This method will call visibilityChanged() and also componentVisibilityChanged() - for any component listeners that are interested in this component. + /** Dumbly adds a rectangle to the list without checking for overlaps. - @param shouldBeVisible whether to show or hide the component - @see isVisible, isShowing, visibilityChanged, ComponentListener::componentVisibilityChanged + This simply adds the rectangle to the end, it doesn't merge it or remove + any overlapping bits. */ - virtual void setVisible (bool shouldBeVisible); - - /** Tests whether the component is visible or not. + void addWithoutMerging (const Rectangle& rect) throw(); - this doesn't necessarily tell you whether this comp is actually on the screen - because this depends on whether all the parent components are also visible - use - isShowing() to find this out. + /** Merges another rectangle list into this one. - @see isShowing, setVisible + Any overlaps between the two lists will be clipped, so that the result is + the union of both lists. */ - bool isVisible() const throw() { return flags.visibleFlag; } + void add (const RectangleList& other) throw(); - /** Called when this component's visiblility changes. + /** Removes a rectangular region from the list. - @see setVisible, isVisible + Any rectangles in the list which overlap this will be clipped and subdivided + if necessary. */ - virtual void visibilityChanged(); + void subtract (const Rectangle& rect) throw(); - /** Tests whether this component and all its parents are visible. + /** Removes all areas in another RectangleList from this one. - @returns true only if this component and all its parents are visible. - @see isVisible + Any rectangles in the list which overlap this will be clipped and subdivided + if necessary. */ - bool isShowing() const throw(); - - /** Makes a component invisible using a groovy fade-out and animated zoom effect. + void subtract (const RectangleList& otherList) throw(); - To do this, this function will cunningly: - - take a snapshot of the component as it currently looks - - call setVisible(false) on the component - - replace it with a special component that will continue drawing the - snapshot, animating it and gradually making it more transparent - - when it's gone, the special component will also be deleted + /** Removes any areas of the region that lie outside a given rectangle. - As soon as this method returns, the component can be safely removed and deleted - leaving the proxy to do the fade-out, so it's even ok to call this in a - component's destructor. + Any rectangles in the list which overlap this will be clipped and subdivided + if necessary. - Passing non-zero x and y values will cause the ghostly component image to - also whizz off by this distance while fading out. If the scale factor is - not 1.0, it will also zoom from the component's current size to this new size. + Returns true if the resulting region is not empty, false if it is empty. - One thing to be careful about is that the parent component must be able to cope - with this unknown component type being added to it. + @see getIntersectionWith */ - void fadeOutComponent (const int lengthOfFadeOutInMilliseconds, - const int deltaXToMove = 0, - const int deltaYToMove = 0, - const float scaleFactorAtEnd = 1.0f); + bool clipTo (const Rectangle& rect) throw(); - /** Makes this component appear as a window on the desktop. + /** Removes any areas of the region that lie outside a given rectangle list. - Note that before calling this, you should make sure that the component's opacity is - set correctly using setOpaque(). If the component is non-opaque, the windowing - system will try to create a special transparent window for it, which will generally take - a lot more CPU to operate (and might not even be possible on some platforms). + Any rectangles in this object which overlap the specified list will be clipped + and subdivided if necessary. - If the component is inside a parent component at the time this method is called, it - will be first be removed from that parent. Likewise if a component on the desktop - is subsequently added to another component, it'll be removed from the desktop. + Returns true if the resulting region is not empty, false if it is empty. - @param windowStyleFlags a combination of the flags specified in the - ComponentPeer::StyleFlags enum, which define the - window's characteristics. - @param nativeWindowToAttachTo this allows an OS object to be passed-in as the window - in which the juce component should place itself. On Windows, - this would be a HWND, a HIViewRef on the Mac. Not necessarily - supported on all platforms, and best left as 0 unless you know - what you're doing - @see removeFromDesktop, isOnDesktop, userTriedToCloseWindow, - getPeer, ComponentPeer::setMinimised, ComponentPeer::StyleFlags, - ComponentPeer::getStyleFlags, ComponentPeer::setFullScreen + @see getIntersectionWith */ - virtual void addToDesktop (int windowStyleFlags, - void* nativeWindowToAttachTo = 0); + bool clipTo (const RectangleList& other) throw(); - /** If the component is currently showing on the desktop, this will hide it. + /** Creates a region which is the result of clipping this one to a given rectangle. - You can also use setVisible() to hide a desktop window temporarily, but - removeFromDesktop() will free any system resources that are being used up. + Unlike the other clipTo method, this one doesn't affect this object - it puts the + resulting region into the list whose reference is passed-in. - @see addToDesktop, isOnDesktop + Returns true if the resulting region is not empty, false if it is empty. + + @see clipTo */ - void removeFromDesktop(); + bool getIntersectionWith (const Rectangle& rect, RectangleList& destRegion) const throw(); - /** Returns true if this component is currently showing on the desktop. + /** Swaps the contents of this and another list. - @see addToDesktop, removeFromDesktop + This swaps their internal pointers, so is hugely faster than using copy-by-value + to swap them. */ - bool isOnDesktop() const throw(); + void swapWith (RectangleList& otherList) throw(); - /** Returns the heavyweight window that contains this component. + /** Checks whether the region contains a given point. - If this component is itself on the desktop, this will return the window - object that it is using. Otherwise, it will return the window of - its top-level parent component. + @returns true if the point lies within one of the rectangles in the list + */ + bool containsPoint (const int x, const int y) const throw(); - This may return 0 if there isn't a desktop component. + /** Checks whether the region contains the whole of a given rectangle. - @see addToDesktop, isOnDesktop + @returns true all parts of the rectangle passed in lie within the region + defined by this object + @see intersectsRectangle, containsPoint */ - ComponentPeer* getPeer() const throw(); + bool containsRectangle (const Rectangle& rectangleToCheck) const throw(); - /** For components on the desktop, this is called if the system wants to close the window. + /** Checks whether the region contains any part of a given rectangle. - This is a signal that either the user or the system wants the window to close. The - default implementation of this method will trigger an assertion to warn you that your - component should do something about it, but you can override this to ignore the event - if you want. + @returns true if any part of the rectangle passed in lies within the region + defined by this object + @see containsRectangle */ - virtual void userTriedToCloseWindow(); - - /** Called for a desktop component which has just been minimised or un-minimised. + bool intersectsRectangle (const Rectangle& rectangleToCheck) const throw(); - This will only be called for components on the desktop. + /** Checks whether this region intersects any part of another one. - @see getPeer, ComponentPeer::setMinimised, ComponentPeer::isMinimised + @see intersectsRectangle */ - virtual void minimisationStateChanged (bool isNowMinimised); + bool intersects (const RectangleList& other) const throw(); - /** Brings the component to the front of its siblings. + /** Returns the smallest rectangle that can enclose the whole of this region. */ + const Rectangle getBounds() const throw(); - If some of the component's siblings have had their 'always-on-top' flag set, - then they will still be kept in front of this one (unless of course this - one is also 'always-on-top'). + /** Optimises the list into a minimum number of constituent rectangles. - @param shouldAlsoGainFocus if true, this will also try to assign keyboard focus - to the component (see grabKeyboardFocus() for more details) - @see toBack, toBehind, setAlwaysOnTop + This will try to combine any adjacent rectangles into larger ones where + possible, to simplify lists that might have been fragmented by repeated + add/subtract calls. */ - void toFront (const bool shouldAlsoGainFocus); + void consolidate() throw(); - /** Changes this component's z-order to be at the back of all its siblings. + /** Adds an x and y value to all the co-ordinates. */ + void offsetAll (const int dx, const int dy) throw(); - If the component is set to be 'always-on-top', it will only be moved to the - back of the other other 'always-on-top' components. + /** Creates a Path object to represent this region. */ + const Path toPath() const throw(); - @see toFront, toBehind, setAlwaysOnTop - */ - void toBack(); + /** An iterator for accessing all the rectangles in a RectangleList. */ + class Iterator + { + public: - /** Changes this component's z-order so that it's just behind another component. + Iterator (const RectangleList& list) throw(); + ~Iterator() throw(); - @see toFront, toBack - */ - void toBehind (Component* const other); + /** Advances to the next rectangle, and returns true if it's not finished. - /** Sets whether the component should always be kept at the front of its siblings. + Call this before using getRectangle() to find the rectangle that was returned. + */ + bool next() throw(); - @see isAlwaysOnTop - */ - void setAlwaysOnTop (const bool shouldStayOnTop); + /** Returns the current rectangle. */ + const Rectangle* getRectangle() const throw() { return current; } - /** Returns true if this component is set to always stay in front of its siblings. + juce_UseDebuggingNewOperator - @see setAlwaysOnTop - */ - bool isAlwaysOnTop() const throw(); + private: + const Rectangle* current; + const RectangleList& owner; + int index; - /** Returns the x co-ordinate of the component's left edge. + Iterator (const Iterator&); + const Iterator& operator= (const Iterator&); + }; - This is a distance in pixels from the left edge of the component's parent. + juce_UseDebuggingNewOperator - @see getScreenX - */ - inline int getX() const throw() { return bounds_.getX(); } +private: + friend class Iterator; + Array rects; +}; - /** Returns the y co-ordinate of the top of this component. +#endif // __JUCE_RECTANGLELIST_JUCEHEADER__ +/********* End of inlined file: juce_RectangleList.h *********/ - This is a distance in pixels from the top edge of the component's parent. +/********* Start of inlined file: juce_BorderSize.h *********/ +#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ +#define __JUCE_BORDERSIZE_JUCEHEADER__ - @see getScreenY - */ - inline int getY() const throw() { return bounds_.getY(); } +/** + Specifies a set of gaps to be left around the sides of a rectangle. - /** Returns the component's width in pixels. */ - inline int getWidth() const throw() { return bounds_.getWidth(); } + This is basically the size of the spaces at the top, bottom, left and right of + a rectangle. It's used by various component classes to specify borders. - /** Returns the component's height in pixels. */ - inline int getHeight() const throw() { return bounds_.getHeight(); } + @see Rectangle +*/ +class JUCE_API BorderSize +{ +public: - /** Returns the x co-ordinate of the component's right-hand edge. + /** Creates a null border. - This is a distance in pixels from the left edge of the component's parent. + All sizes are left as 0. */ - int getRight() const throw() { return bounds_.getRight(); } + BorderSize() throw(); - /** Returns the y co-ordinate of the bottom edge of this component. + /** Creates a copy of another border. */ + BorderSize (const BorderSize& other) throw(); - This is a distance in pixels from the top edge of the component's parent. - */ - int getBottom() const throw() { return bounds_.getBottom(); } + /** Creates a border with the given gaps. */ + BorderSize (const int topGap, + const int leftGap, + const int bottomGap, + const int rightGap) throw(); - /** Returns this component's bounding box. + /** Creates a border with the given gap on all sides. */ + BorderSize (const int allGaps) throw(); - The rectangle returned is relative to the top-left of the component's parent. - */ - const Rectangle& getBounds() const throw() { return bounds_; } + /** Destructor. */ + ~BorderSize() throw(); - /** Returns the region of this component that's not obscured by other, opaque components. + /** Returns the gap that should be left at the top of the region. */ + int getTop() const throw() { return top; } - The RectangleList that is returned represents the area of this component - which isn't covered by opaque child components. + /** Returns the gap that should be left at the top of the region. */ + int getLeft() const throw() { return left; } - If includeSiblings is true, it will also take into account any siblings - that may be overlapping the component. - */ - void getVisibleArea (RectangleList& result, - const bool includeSiblings) const; + /** Returns the gap that should be left at the top of the region. */ + int getBottom() const throw() { return bottom; } - /** Returns this component's x co-ordinate relative the the screen's top-left origin. + /** Returns the gap that should be left at the top of the region. */ + int getRight() const throw() { return right; } - @see getX, relativePositionToGlobal - */ - int getScreenX() const throw(); + /** Returns the sum of the top and bottom gaps. */ + int getTopAndBottom() const throw() { return top + bottom; } - /** Returns this component's y co-ordinate relative the the screen's top-left origin. + /** Returns the sum of the left and right gaps. */ + int getLeftAndRight() const throw() { return left + right; } - @see getY, relativePositionToGlobal - */ - int getScreenY() const throw(); + /** Changes the top gap. */ + void setTop (const int newTopGap) throw(); - /** Converts a position relative to this component's top-left into a screen co-ordinate. + /** Changes the left gap. */ + void setLeft (const int newLeftGap) throw(); - @see globalPositionToRelative, relativePositionToOtherComponent - */ - void relativePositionToGlobal (int& x, int& y) const throw(); + /** Changes the bottom gap. */ + void setBottom (const int newBottomGap) throw(); - /** Converts a screen co-ordinate into a position relative to this component's top-left. + /** Changes the right gap. */ + void setRight (const int newRightGap) throw(); - @see relativePositionToGlobal, relativePositionToOtherComponent - */ - void globalPositionToRelative (int& x, int& y) const throw(); + /** Returns a rectangle with these borders removed from it. */ + const Rectangle subtractedFrom (const Rectangle& original) const throw(); - /** Converts a position relative to this component's top-left into a position - relative to another component's top-left. + /** Removes this border from a given rectangle. */ + void subtractFrom (Rectangle& rectangle) const throw(); - @see relativePositionToGlobal, globalPositionToRelative - */ - void relativePositionToOtherComponent (const Component* const targetComponent, - int& x, int& y) const throw(); + /** Returns a rectangle with these borders added around it. */ + const Rectangle addedTo (const Rectangle& original) const throw(); - /** Moves the component to a new position. + /** Adds this border around a given rectangle. */ + void addTo (Rectangle& original) const throw(); - Changes the component's top-left position (without changing its size). - The position is relative to the top-left of the component's parent. + bool operator== (const BorderSize& other) const throw(); + bool operator!= (const BorderSize& other) const throw(); - If the component actually moves, this method will make a synchronous call to moved(). + juce_UseDebuggingNewOperator - @see setBounds, ComponentListener::componentMovedOrResized - */ - void setTopLeftPosition (const int x, const int y); +private: + int top, left, bottom, right; +}; - /** Moves the component to a new position. +#endif // __JUCE_BORDERSIZE_JUCEHEADER__ +/********* End of inlined file: juce_BorderSize.h *********/ - Changes the position of the component's top-right corner (keeping it the same size). - The position is relative to the top-left of the component's parent. +/********* Start of inlined file: juce_ComponentPeer.h *********/ +#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ +#define __JUCE_COMPONENTPEER_JUCEHEADER__ - If the component actually moves, this method will make a synchronous call to moved(). - */ - void setTopRightPosition (const int x, const int y); +class Component; +class Graphics; - /** Changes the size of the component. +class ComponentBoundsConstrainer; +class ComponentDeletionWatcher; - A synchronous call to resized() will be occur if the size actually changes. - */ - void setSize (const int newWidth, const int newHeight); +/** + The base class for window objects that wrap a component as a real operating + system object. - /** Changes the component's position and size. + This is an abstract base class - the platform specific code contains default + implementations of it that create and manage windows. - The co-ordinates are relative to the top-left of the component's parent, or relative - to the origin of the screen is the component is on the desktop. + @see Component::createNewPeer +*/ +class JUCE_API ComponentPeer : public MessageListener +{ +public: - If this method changes the component's top-left position, it will make a synchronous - call to moved(). If it changes the size, it will also make a call to resized(). + /** A combination of these flags is passed to the ComponentPeer constructor. */ + enum StyleFlags + { + windowAppearsOnTaskbar = (1 << 0), /**< Indicates that the window should have a corresponding + entry on the taskbar (ignored on MacOSX) */ + windowIsTemporary = (1 << 1), /**< Indicates that the window is a temporary popup, like a menu, + tooltip, etc. */ + windowIgnoresMouseClicks = (1 << 2), /**< Indicates that the window should let mouse clicks pass + through it (may not be possible on some platforms). */ + windowHasTitleBar = (1 << 3), /**< Indicates that the window should have a normal OS-specific + title bar and frame\. if not specified, the window will be + borderless. */ + windowIsResizable = (1 << 4), /**< Indicates that the window should have a resizable border. */ + windowHasMinimiseButton = (1 << 5), /**< Indicates that if the window has a title bar, it should have a + minimise button on it. */ + windowHasMaximiseButton = (1 << 6), /**< Indicates that if the window has a title bar, it should have a + maximise button on it. */ + windowHasCloseButton = (1 << 7), /**< Indicates that if the window has a title bar, it should have a + close button on it. */ + windowHasDropShadow = (1 << 8), /**< Indicates that the window should have a drop-shadow (this may + not be possible on all platforms). */ + windowRepaintedExplictly = (1 << 9), /**< Not intended for public use - this tells a window not to + do its own repainting, but only to repaint when the + performAnyPendingRepaintsNow() method is called. */ + windowIgnoresKeyPresses = (1 << 10), /**< Tells the window not to catch any keypresses. This can + be used for things like plugin windows, to stop them interfering + with the host's shortcut keys */ + windowIsSemiTransparent = (1 << 31) /**< Not intended for public use - makes a window transparent. */ - @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized - */ - void setBounds (int x, int y, int width, int height); + }; - /** Changes the component's position and size. + /** Creates a peer. - @see setBounds + The component is the one that we intend to represent, and the style flags are + a combination of the values in the StyleFlags enum */ - void setBounds (const Rectangle& newBounds); + ComponentPeer (Component* const component, + const int styleFlags) throw(); - /** Changes the component's position and size in terms of fractions of its parent's size. + /** Destructor. */ + virtual ~ComponentPeer(); - The values are factors of the parent's size, so for example - setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the - width and height of the parent, with its top-left position 20% of - the way across and down the parent. + /** Returns the component being represented by this peer. */ + Component* getComponent() const throw() { return component; } + + /** Returns the set of style flags that were set when the window was created. + + @see Component::addToDesktop */ - void setBoundsRelative (const float proportionalX, const float proportionalY, - const float proportionalWidth, const float proportionalHeight); + int getStyleFlags() const throw() { return styleFlags; } - /** Changes the component's position and size based on the amount of space to leave around it. + /** Returns the raw handle to whatever kind of window is being used. - This will position the component within its parent, leaving the specified number of - pixels around each edge. + On windows, this is probably a HWND, on the mac, it's likely to be a WindowRef, + but rememeber there's no guarantees what you'll get back. */ - void setBoundsInset (const BorderSize& borders); + virtual void* getNativeHandle() const = 0; - /** Positions the component within a given rectangle, keeping its proportions - unchanged. + /** Shows or hides the window. */ + virtual void setVisible (bool shouldBeVisible) = 0; - If onlyReduceInSize is false, the component will be resized to fill as much of the - rectangle as possible without changing its aspect ratio (the component's - current size is used to determine its aspect ratio, so a zero-size component - won't work here). If onlyReduceInSize is true, it will only be resized if it's - too big to fit inside the rectangle. + /** Changes the title of the window. */ + virtual void setTitle (const String& title) = 0; - It will then be positioned within the rectangle according to the justification flags - specified. - */ - void setBoundsToFit (int x, int y, int width, int height, - const Justification& justification, - const bool onlyReduceInSize); + /** Moves the window without changing its size. - /** Changes the position of the component's centre. + If the native window is contained in another window, then the co-ordinates are + relative to the parent window's origin, not the screen origin. - Leaves the component's size unchanged, but sets the position of its centre - relative to its parent's top-left. + This should result in a callback to handleMovedOrResized(). */ - void setCentrePosition (const int x, const int y); + virtual void setPosition (int x, int y) = 0; - /** Changes the position of the component's centre. + /** Resizes the window without changing its position. - Leaves the position unchanged, but positions its centre relative to its - parent's size. E.g. setCentreRelative (0.5f, 0.5f) would place it centrally in - its parent. + This should result in a callback to handleMovedOrResized(). */ - void setCentreRelative (const float x, const float y); + virtual void setSize (int w, int h) = 0; - /** Changes the component's size and centres it within its parent. + /** Moves and resizes the window. - After changing the size, the component will be moved so that it's - centred within its parent. + If the native window is contained in another window, then the co-ordinates are + relative to the parent window's origin, not the screen origin. + + This should result in a callback to handleMovedOrResized(). */ - void centreWithSize (const int width, const int height); + virtual void setBounds (int x, int y, int w, int h, const bool isNowFullScreen) = 0; - /** Returns a proportion of the component's width. + /** Returns the current position and size of the window. - This is a handy equivalent of (getWidth() * proportion). + If the native window is contained in another window, then the co-ordinates are + relative to the parent window's origin, not the screen origin. */ - int proportionOfWidth (const float proportion) const throw(); + virtual void getBounds (int& x, int& y, int& w, int& h) const = 0; - /** Returns a proportion of the component's height. + /** Returns the x-position of this window, relative to the screen's origin. */ + virtual int getScreenX() const = 0; - This is a handy equivalent of (getHeight() * proportion). - */ - int proportionOfHeight (const float proportion) const throw(); + /** Returns the y-position of this window, relative to the screen's origin. */ + virtual int getScreenY() const = 0; - /** Returns the width of the component's parent. + /** Converts a position relative to the top-left of this component to screen co-ordinates. */ + virtual void relativePositionToGlobal (int& x, int& y) = 0; - If the component has no parent (i.e. if it's on the desktop), this will return - the width of the screen. - */ - int getParentWidth() const throw(); + /** Converts a screen co-ordinate to a position relative to the top-left of this component. */ + virtual void globalPositionToRelative (int& x, int& y) = 0; - /** Returns the height of the component's parent. + /** Minimises the window. */ + virtual void setMinimised (bool shouldBeMinimised) = 0; - If the component has no parent (i.e. if it's on the desktop), this will return - the height of the screen. - */ - int getParentHeight() const throw(); + /** True if the window is currently minimised. */ + virtual bool isMinimised() const = 0; - /** Returns the screen co-ordinates of the monitor that contains this component. + /** Enable/disable fullscreen mode for the window. */ + virtual void setFullScreen (bool shouldBeFullScreen) = 0; - If there's only one monitor, this will return its size - if there are multiple - monitors, it will return the area of the monitor that contains the component's - centre. + /** True if the window is currently full-screen. */ + virtual bool isFullScreen() const = 0; + + /** Sets the size to restore to if fullscreen mode is turned off. */ + void setNonFullScreenBounds (const Rectangle& newBounds) throw(); + + /** Returns the size to restore to if fullscreen mode is turned off. */ + const Rectangle& getNonFullScreenBounds() const throw(); + + /** Attempts to change the icon associated with this window. */ - const Rectangle getParentMonitorArea() const throw(); + virtual void setIcon (const Image& newIcon) = 0; - /** Returns the number of child components that this component contains. + /** Sets a constrainer to use if the peer can resize itself. - @see getChildComponent, getIndexOfChildComponent + The constrainer won't be deleted by this object, so the caller must manage its lifetime. */ - int getNumChildComponents() const throw(); + void setConstrainer (ComponentBoundsConstrainer* const newConstrainer) throw(); - /** Returns one of this component's child components, by it index. + /** Returns the current constrainer, if one has been set. */ + ComponentBoundsConstrainer* getConstrainer() const throw() { return constrainer; } - The component with index 0 is at the back of the z-order, the one at the - front will have index (getNumChildComponents() - 1). + /** Checks if a point is in the window. - If the index is out-of-range, this will return a null pointer. + Coordinates are relative to the top-left of this window. If trueIfInAChildWindow + is false, then this returns false if the point is actually inside a child of this + window. + */ + virtual bool contains (int x, int y, bool trueIfInAChildWindow) const = 0; - @see getNumChildComponents, getIndexOfChildComponent + /** Returns the size of the window frame that's around this window. + + Whether or not the window has a normal window frame depends on the flags + that were set when the window was created by Component::addToDesktop() */ - Component* getChildComponent (const int index) const throw(); + virtual const BorderSize getFrameSize() const = 0; - /** Returns the index of this component in the list of child components. + /** This is called when the window's bounds change. - A value of 0 means it is first in the list (i.e. behind all other components). Higher - values are further towards the front. + A peer implementation must call this when the window is moved and resized, so that + this method can pass the message on to the component. + */ + void handleMovedOrResized(); - Returns -1 if the component passed-in is not a child of this component. + /** This is called if the screen resolution changes. - @see getNumChildComponents, getChildComponent, addChildComponent, toFront, toBack, toBehind + A peer implementation must call this if the monitor arrangement changes or the available + screen size changes. */ - int getIndexOfChildComponent (const Component* const child) const throw(); + void handleScreenSizeChange(); - /** Adds a child component to this one. + /** This is called to repaint the component into the given context. */ + void handlePaint (LowLevelGraphicsContext& contextToPaintTo); - @param child the new component to add. If the component passed-in is already - the child of another component, it'll first be removed from that. + /** Sets this window to either be always-on-top or normal. - @param zOrder The index in the child-list at which this component should be inserted. - A value of -1 will insert it in front of the others, 0 is the back. - @see removeChildComponent, addAndMakeVisible, getChild, - ComponentListener::componentChildrenChanged + Some kinds of window might not be able to do this, so should return false. */ - void addChildComponent (Component* const child, - int zOrder = -1); + virtual bool setAlwaysOnTop (bool alwaysOnTop) = 0; - /** Adds a child component to this one, and also makes the child visible if it isn't. + /** Brings the window to the top, optionally also giving it focus. */ + virtual void toFront (bool makeActive) = 0; - Quite a useful function, this is just the same as calling addChildComponent() - followed by setVisible (true) on the child. + /** Moves the window to be just behind another one. */ + virtual void toBehind (ComponentPeer* other) = 0; + + /** Called when the window is brought to the front, either by the OS or by a call + to toFront(). */ - void addAndMakeVisible (Component* const child, - int zOrder = -1); + void handleBroughtToFront(); - /** Removes one of this component's child-components. + /** True if the window has the keyboard focus. */ + virtual bool isFocused() const = 0; - If the child passed-in isn't actually a child of this component (either because - it's invalid or is the child of a different parent), then nothing is done. + /** Tries to give the window keyboard focus. */ + virtual void grabFocus() = 0; - Note that removing a child will not delete it! + /** Tells the window that text input may be required at the given position. - @see addChildComponent, ComponentListener::componentChildrenChanged + This may cause things like a virtual on-screen keyboard to appear, depending + on the OS. */ - void removeChildComponent (Component* const childToRemove); + virtual void textInputRequired (int x, int y) = 0; - /** Removes one of this component's child-components by index. + /** Called when the window gains keyboard focus. */ + void handleFocusGain(); + /** Called when the window loses keyboard focus. */ + void handleFocusLoss(); - This will return a pointer to the component that was removed, or null if - the index was out-of-range. + Component* getLastFocusedSubcomponent() const throw(); - Note that removing a child will not delete it! + /** Called when a key is pressed. - @see addChildComponent, ComponentListener::componentChildrenChanged + For keycode info, see the KeyPress class. + Returns true if the keystroke was used. */ - Component* removeChildComponent (const int childIndexToRemove); - - /** Removes all this component's children. + bool handleKeyPress (const int keyCode, + const juce_wchar textCharacter); - Note that this won't delete them! To do that, use deleteAllChildren() instead. + /** Called whenever a key is pressed or released. + Returns true if the keystroke was used. */ - void removeAllChildren(); + bool handleKeyUpOrDown (const bool isKeyDown); - /** Removes all this component's children, and deletes them. + /** Called whenever a modifier key is pressed or released. */ + void handleModifierKeysChange(); - @see removeAllChildren - */ - void deleteAllChildren(); + /** Invalidates a region of the window to be repainted asynchronously. */ + virtual void repaint (int x, int y, int w, int h) = 0; - /** Returns the component which this component is inside. + /** This can be called (from the message thread) to cause the immediate redrawing + of any areas of this window that need repainting. - If this is the highest-level component or hasn't yet been added to - a parent, this will return null. + You shouldn't ever really need to use this, it's mainly for special purposes + like supporting audio plugins where the host's event loop is out of our control. */ - Component* getParentComponent() const throw() { return parentComponent_; } + virtual void performAnyPendingRepaintsNow() = 0; - /** Searches the parent components for a component of a specified class. + void handleMouseEnter (int x, int y, const int64 time); + void handleMouseMove (int x, int y, const int64 time); + void handleMouseDown (int x, int y, const int64 time); + void handleMouseDrag (int x, int y, const int64 time); + void handleMouseUp (const int oldModifiers, int x, int y, const int64 time); + void handleMouseExit (int x, int y, const int64 time); + void handleMouseWheel (const int amountX, const int amountY, const int64 time); - For example findParentComponentOfClass \() would return the first parent - component that can be dynamically cast to a MyComp, or will return 0 if none - of the parents are suitable. + /** Causes a mouse-move callback to be made asynchronously. */ + void sendFakeMouseMove() throw(); - N.B. The dummy parameter is needed to work around a VC6 compiler bug. - */ - template - TargetClass* findParentComponentOfClass (TargetClass* const dummyParameter = 0) const - { - (void) dummyParameter; - Component* p = parentComponent_; - while (p != 0) - { - TargetClass* target = dynamic_cast (p); - if (target != 0) - return target; + void handleUserClosingWindow(); - p = p->parentComponent_; - } + void handleFileDragMove (const StringArray& files, int x, int y); + void handleFileDragExit (const StringArray& files); + void handleFileDragDrop (const StringArray& files, int x, int y); - return 0; - } + /** Resets the masking region. - /** Returns the highest-level component which contains this one or its parents. + The subclass should call this every time it's about to call the handlePaint + method. - This will search upwards in the parent-hierarchy from this component, until it - finds the highest one that doesn't have a parent (i.e. is on the desktop or - not yet added to a parent), and will return that. + @see addMaskedRegion */ - Component* getTopLevelComponent() const throw(); + void clearMaskedRegion() throw(); - /** Checks whether a component is anywhere inside this component or its children. + /** Adds a rectangle to the set of areas not to paint over. - This will recursively check through this components children to see if the - given component is anywhere inside. + A component can call this on its peer during its paint() method, to signal + that the painting code should ignore a given region. The reason + for this is to stop embedded windows (such as OpenGL) getting painted over. + + The masked region is cleared each time before a paint happens, so a component + will have to make sure it calls this every time it's painted. */ - bool isParentOf (const Component* possibleChild) const throw(); + void addMaskedRegion (int x, int y, int w, int h) throw(); - /** Called to indicate that the component's parents have changed. + /** Returns the number of currently-active peers. - When a component is added or removed from its parent, this method will - be called on all of its children (recursively - so all children of its - children will also be called as well). + @see getPeer + */ + static int getNumPeers() throw(); - Subclasses can override this if they need to react to this in some way. + /** Returns one of the currently-active peers. - @see getParentComponent, isShowing, ComponentListener::componentParentHierarchyChanged + @see getNumPeers */ - virtual void parentHierarchyChanged(); + static ComponentPeer* getPeer (const int index) throw(); - /** Subclasses can use this callback to be told when children are added or removed. + /** Checks if this peer object is valid. - @see parentHierarchyChanged + @see getNumPeers */ - virtual void childrenChanged(); - - /** Tests whether a given point inside the component. + static bool isValidPeer (const ComponentPeer* const peer) throw(); - Overriding this method allows you to create components which only intercept - mouse-clicks within a user-defined area. + static void bringModalComponentToFront(); - This is called to find out whether a particular x, y co-ordinate is - considered to be inside the component or not, and is used by methods such - as contains() and getComponentAt() to work out which component - the mouse is clicked on. + virtual const StringArray getAvailableRenderingEngines() throw(); + virtual int getCurrentRenderingEngine() throw(); + virtual void setCurrentRenderingEngine (int index) throw(); - Components with custom shapes will probably want to override it to perform - some more complex hit-testing. + juce_UseDebuggingNewOperator - The default implementation of this method returns either true or false, - depending on the value that was set by calling setInterceptsMouseClicks() (true - is the default return value). +protected: + Component* const component; + const int styleFlags; + RectangleList maskedRegion; + Rectangle lastNonFullscreenBounds; + uint32 lastPaintTime; + ComponentBoundsConstrainer* constrainer; - Note that the hit-test region is not related to the opacity with which - areas of a component are painted. + static void updateCurrentModifiers() throw(); - Applications should never call hitTest() directly - instead use the - contains() method, because this will also test for occlusion by the - component's parent. + /** @internal */ + void handleMessage (const Message& message); - Note that for components on the desktop, this method will be ignored, because it's - not always possible to implement this behaviour on all platforms. +private: - @param x the x co-ordinate to test, relative to the left hand edge of this - component. This value is guaranteed to be greater than or equal to - zero, and less than the component's width - @param y the y co-ordinate to test, relative to the top edge of this - component. This value is guaranteed to be greater than or equal to - zero, and less than the component's height - @returns true if the click is considered to be inside the component - @see setInterceptsMouseClicks, contains - */ - virtual bool hitTest (int x, int y); + Component* lastFocusedComponent; + ComponentDeletionWatcher* dragAndDropTargetComponent; + Component* lastDragAndDropCompUnderMouse; + bool fakeMouseMessageSent : 1, isWindowMinimised : 1; - /** Changes the default return value for the hitTest() method. + friend class Component; + static ComponentPeer* getPeerFor (const Component* const component) throw(); - Setting this to false is an easy way to make a component pass its mouse-clicks - through to the components behind it. + void setLastDragDropTarget (Component* comp); - When a component is created, the default setting for this is true. + ComponentPeer (const ComponentPeer&); + const ComponentPeer& operator= (const ComponentPeer&); +}; - @param allowClicksOnThisComponent if true, hitTest() will always return true; if false, it will - return false (or true for child components if allowClicksOnChildComponents - is true) - @param allowClicksOnChildComponents if this is true and allowClicksOnThisComponent is false, then child - components can be clicked on as normal but clicks on this component pass - straight through; if this is false and allowClicksOnThisComponent - is false, then neither this component nor any child components can - be clicked on - @see hitTest, getInterceptsMouseClicks - */ - void setInterceptsMouseClicks (const bool allowClicksOnThisComponent, - const bool allowClicksOnChildComponents) throw(); +#endif // __JUCE_COMPONENTPEER_JUCEHEADER__ +/********* End of inlined file: juce_ComponentPeer.h *********/ - /** Retrieves the current state of the mouse-click interception flags. +class LookAndFeel; - On return, the two parameters are set to the state used in the last call to - setInterceptsMouseClicks(). +/** + The base class for all JUCE user-interface objects. - @see setInterceptsMouseClicks - */ - void getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, - bool& allowsClicksOnChildComponents) const throw(); +*/ +class JUCE_API Component : public MouseListener, + protected MessageListener +{ +public: - /** Returns true if a given point lies within this component or one of its children. + /** Creates a component. - Never override this method! Use hitTest to create custom hit regions. + To get it to actually appear, you'll also need to: + - Either add it to a parent component or use the addToDesktop() method to + make it a desktop window + - Set its size and position to something sensible + - Use setVisible() to make it visible - @param x the x co-ordinate to test, relative to this component's left hand edge. - @param y the y co-ordinate to test, relative to this component's top edge. - @returns true if the point is within the component's hit-test area, but only if - that part of the component isn't clipped by its parent component. Note - that this won't take into account any overlapping sibling components - which might be in the way - for that, see reallyContains() - @see hitTest, reallyContains, getComponentAt + And for it to serve any useful purpose, you'll need to write a + subclass of Component or use one of the other types of component from + the library. */ - virtual bool contains (int x, int y); - - /** Returns true if a given point lies in this component, taking any overlapping - siblings into account. + Component() throw(); - @param x the x co-ordinate to test, relative to this component's left hand edge. - @param y the y co-ordinate to test, relative to this component's top edge. - @param returnTrueIfWithinAChild if the point actually lies within a child of this - component, this determines the value that will - be returned. + /** Destructor. - @see contains, getComponentAt + Note that when a component is deleted, any child components it might + contain are NOT deleted unless you explicitly call deleteAllChildren() first. */ - bool reallyContains (int x, int y, - const bool returnTrueIfWithinAChild); + virtual ~Component(); - /** Returns the component at a certain point within this one. + /** Creates a component, setting its name at the same time. - @param x the x co-ordinate to test, relative to this component's left hand edge. - @param y the y co-ordinate to test, relative to this component's top edge. - @returns the component that is at this position - which may be 0, this component, - or one of its children. Note that overlapping siblings that might actually - be in the way are not taken into account by this method - to account for these, - instead call getComponentAt on the top-level parent of this component. - @see hitTest, contains, reallyContains + @see getName, setName */ - Component* getComponentAt (const int x, const int y); + Component (const String& componentName) throw(); - /** Marks the whole component as needing to be redrawn. + /** Returns the name of this component. - Calling this will not do any repainting immediately, but will mark the component - as 'dirty'. At some point in the near future the operating system will send a paint - message, which will redraw all the dirty regions of all components. - There's no guarantee about how soon after calling repaint() the redraw will actually - happen, and other queued events may be delivered before a redraw is done. + @see setName + */ + const String& getName() const throw() { return componentName_; } - If the setBufferedToImage() method has been used to cause this component - to use a buffer, the repaint() call will invalidate the component's buffer. + /** Sets the name of this component. - To redraw just a subsection of the component rather than the whole thing, - use the repaint (int, int, int, int) method. + When the name changes, all registered ComponentListeners will receive a + ComponentListener::componentNameChanged() callback. - @see paint + @see getName */ - void repaint() throw(); - - /** Marks a subsection of this component as needing to be redrawn. + virtual void setName (const String& newName); - Calling this will not do any repainting immediately, but will mark the given region - of the component as 'dirty'. At some point in the near future the operating system - will send a paint message, which will redraw all the dirty regions of all components. - There's no guarantee about how soon after calling repaint() the redraw will actually - happen, and other queued events may be delivered before a redraw is done. + /** Checks whether this Component object has been deleted. - The region that is passed in will be clipped to keep it within the bounds of this - component. + This will check whether this object is still a valid component, or whether + it's been deleted. - @see repaint() + It's safe to call this on null or dangling pointers, but note that there is a + small risk if another new (but different) component has been created at the + same memory address which this one occupied, this methods can return a + false positive. */ - void repaint (const int x, const int y, - const int width, const int height) throw(); - - /** Makes the component use an internal buffer to optimise its redrawing. + bool isValidComponent() const throw(); - Setting this flag to true will cause the component to allocate an - internal buffer into which it paints itself, so that when asked to - redraw itself, it can use this buffer rather than actually calling the - paint() method. + /** Makes the component visible or invisible. - The buffer is kept until the repaint() method is called directly on - this component (or until it is resized), when the image is invalidated - and then redrawn the next time the component is painted. + This method will show or hide the component. + Note that components default to being non-visible when first created. + Also note that visible components won't be seen unless all their parent components + are also visible. - Note that only the drawing that happens within the component's paint() - method is drawn into the buffer, it's child components are not buffered, and - nor is the paintOverChildren() method. + This method will call visibilityChanged() and also componentVisibilityChanged() + for any component listeners that are interested in this component. - @see repaint, paint, createComponentSnapshot + @param shouldBeVisible whether to show or hide the component + @see isVisible, isShowing, visibilityChanged, ComponentListener::componentVisibilityChanged */ - void setBufferedToImage (const bool shouldBeBuffered) throw(); - - /** Generates a snapshot of part of this component. - - This will return a new Image, the size of the rectangle specified, - containing a snapshot of the specified area of the component and all - its children. - - The image may or may not have an alpha-channel, depending on whether the - image is opaque or not. + virtual void setVisible (bool shouldBeVisible); - If the clipImageToComponentBounds parameter is true and the area is greater than - the size of the component, it'll be clipped. If clipImageToComponentBounds is false - then parts of the component beyond its bounds can be drawn. + /** Tests whether the component is visible or not. - The caller is responsible for deleting the image that is returned. + this doesn't necessarily tell you whether this comp is actually on the screen + because this depends on whether all the parent components are also visible - use + isShowing() to find this out. - @see paintEntireComponent + @see isShowing, setVisible */ - Image* createComponentSnapshot (const Rectangle& areaToGrab, - const bool clipImageToComponentBounds = true); + bool isVisible() const throw() { return flags.visibleFlag; } - /** Draws this component and all its subcomponents onto the specified graphics - context. + /** Called when this component's visiblility changes. - You should very rarely have to use this method, it's simply there in case you need - to draw a component with a custom graphics context for some reason, e.g. for - creating a snapshot of the component. + @see setVisible, isVisible + */ + virtual void visibilityChanged(); - It calls paint(), paintOverChildren() and recursively calls paintEntireComponent() - on its children in order to render the entire tree. + /** Tests whether this component and all its parents are visible. - The graphics context may be left in an undefined state after this method returns, - so you may need to reset it if you're going to use it again. + @returns true only if this component and all its parents are visible. + @see isVisible */ - void paintEntireComponent (Graphics& context); + bool isShowing() const throw(); - /** Adds an effect filter to alter the component's appearance. + /** Makes a component invisible using a groovy fade-out and animated zoom effect. - When a component has an effect filter set, then this is applied to the - results of its paint() method. There are a few preset effects, such as - a drop-shadow or glow, but they can be user-defined as well. + To do this, this function will cunningly: + - take a snapshot of the component as it currently looks + - call setVisible(false) on the component + - replace it with a special component that will continue drawing the + snapshot, animating it and gradually making it more transparent + - when it's gone, the special component will also be deleted - The effect that is passed in will not be deleted by the component - the - caller must take care of deleting it. + As soon as this method returns, the component can be safely removed and deleted + leaving the proxy to do the fade-out, so it's even ok to call this in a + component's destructor. - To remove an effect from a component, pass a null pointer in as the parameter. + Passing non-zero x and y values will cause the ghostly component image to + also whizz off by this distance while fading out. If the scale factor is + not 1.0, it will also zoom from the component's current size to this new size. - @see ImageEffectFilter, DropShadowEffect, GlowEffect + One thing to be careful about is that the parent component must be able to cope + with this unknown component type being added to it. */ - void setComponentEffect (ImageEffectFilter* const newEffect); + void fadeOutComponent (const int lengthOfFadeOutInMilliseconds, + const int deltaXToMove = 0, + const int deltaYToMove = 0, + const float scaleFactorAtEnd = 1.0f); - /** Returns the current component effect. + /** Makes this component appear as a window on the desktop. - @see setComponentEffect + Note that before calling this, you should make sure that the component's opacity is + set correctly using setOpaque(). If the component is non-opaque, the windowing + system will try to create a special transparent window for it, which will generally take + a lot more CPU to operate (and might not even be possible on some platforms). + + If the component is inside a parent component at the time this method is called, it + will be first be removed from that parent. Likewise if a component on the desktop + is subsequently added to another component, it'll be removed from the desktop. + + @param windowStyleFlags a combination of the flags specified in the + ComponentPeer::StyleFlags enum, which define the + window's characteristics. + @param nativeWindowToAttachTo this allows an OS object to be passed-in as the window + in which the juce component should place itself. On Windows, + this would be a HWND, a HIViewRef on the Mac. Not necessarily + supported on all platforms, and best left as 0 unless you know + what you're doing + @see removeFromDesktop, isOnDesktop, userTriedToCloseWindow, + getPeer, ComponentPeer::setMinimised, ComponentPeer::StyleFlags, + ComponentPeer::getStyleFlags, ComponentPeer::setFullScreen */ - ImageEffectFilter* getComponentEffect() const throw() { return effect_; } + virtual void addToDesktop (int windowStyleFlags, + void* nativeWindowToAttachTo = 0); - /** Finds the appropriate look-and-feel to use for this component. + /** If the component is currently showing on the desktop, this will hide it. - If the component hasn't had a look-and-feel explicitly set, this will - return the parent's look-and-feel, or just the default one if there's no - parent. + You can also use setVisible() to hide a desktop window temporarily, but + removeFromDesktop() will free any system resources that are being used up. - @see setLookAndFeel, lookAndFeelChanged + @see addToDesktop, isOnDesktop */ - LookAndFeel& getLookAndFeel() const throw(); + void removeFromDesktop(); - /** Sets the look and feel to use for this component. + /** Returns true if this component is currently showing on the desktop. - This will also change the look and feel for any child components that haven't - had their look set explicitly. + @see addToDesktop, removeFromDesktop + */ + bool isOnDesktop() const throw(); - The object passed in will not be deleted by the component, so it's the caller's - responsibility to manage it. It may be used at any time until this component - has been deleted. + /** Returns the heavyweight window that contains this component. - Calling this method will also invoke the sendLookAndFeelChange() method. + If this component is itself on the desktop, this will return the window + object that it is using. Otherwise, it will return the window of + its top-level parent component. - @see getLookAndFeel, lookAndFeelChanged + This may return 0 if there isn't a desktop component. + + @see addToDesktop, isOnDesktop */ - void setLookAndFeel (LookAndFeel* const newLookAndFeel); + ComponentPeer* getPeer() const throw(); - /** Called to let the component react to a change in the look-and-feel setting. + /** For components on the desktop, this is called if the system wants to close the window. - When the look-and-feel is changed for a component, this will be called in - all its child components, recursively. + This is a signal that either the user or the system wants the window to close. The + default implementation of this method will trigger an assertion to warn you that your + component should do something about it, but you can override this to ignore the event + if you want. + */ + virtual void userTriedToCloseWindow(); - It can also be triggered manually by the sendLookAndFeelChange() method, in case - an application uses a LookAndFeel class that might have changed internally. + /** Called for a desktop component which has just been minimised or un-minimised. - @see sendLookAndFeelChange, getLookAndFeel + This will only be called for components on the desktop. + + @see getPeer, ComponentPeer::setMinimised, ComponentPeer::isMinimised */ - virtual void lookAndFeelChanged(); + virtual void minimisationStateChanged (bool isNowMinimised); - /** Calls the lookAndFeelChanged() method in this component and all its children. + /** Brings the component to the front of its siblings. - This will recurse through the children and their children, calling lookAndFeelChanged() - on them all. + If some of the component's siblings have had their 'always-on-top' flag set, + then they will still be kept in front of this one (unless of course this + one is also 'always-on-top'). - @see lookAndFeelChanged + @param shouldAlsoGainFocus if true, this will also try to assign keyboard focus + to the component (see grabKeyboardFocus() for more details) + @see toBack, toBehind, setAlwaysOnTop */ - void sendLookAndFeelChange(); + void toFront (const bool shouldAlsoGainFocus); - /** Indicates whether any parts of the component might be transparent. + /** Changes this component's z-order to be at the back of all its siblings. - Components that always paint all of their contents with solid colour and - thus completely cover any components behind them should use this method - to tell the repaint system that they are opaque. + If the component is set to be 'always-on-top', it will only be moved to the + back of the other other 'always-on-top' components. - This information is used to optimise drawing, because it means that - objects underneath opaque windows don't need to be painted. + @see toFront, toBehind, setAlwaysOnTop + */ + void toBack(); - By default, components are considered transparent, unless this is used to - make it otherwise. + /** Changes this component's z-order so that it's just behind another component. - @see isOpaque, getVisibleArea + @see toFront, toBack */ - void setOpaque (const bool shouldBeOpaque) throw(); + void toBehind (Component* const other); - /** Returns true if no parts of this component are transparent. + /** Sets whether the component should always be kept at the front of its siblings. - @returns the value that was set by setOpaque, (the default being false) - @see setOpaque + @see isAlwaysOnTop */ - bool isOpaque() const throw(); + void setAlwaysOnTop (const bool shouldStayOnTop); - /** Indicates whether the component should be brought to the front when clicked. + /** Returns true if this component is set to always stay in front of its siblings. - Setting this flag to true will cause the component to be brought to the front - when the mouse is clicked somewhere inside it or its child components. + @see setAlwaysOnTop + */ + bool isAlwaysOnTop() const throw(); - Note that a top-level desktop window might still be brought to the front by the - operating system when it's clicked, depending on how the OS works. + /** Returns the x co-ordinate of the component's left edge. - By default this is set to false. + This is a distance in pixels from the left edge of the component's parent. - @see setMouseClickGrabsKeyboardFocus + @see getScreenX */ - void setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) throw(); + inline int getX() const throw() { return bounds_.getX(); } - /** Indicates whether the component should be brought to the front when clicked-on. + /** Returns the y co-ordinate of the top of this component. - @see setBroughtToFrontOnMouseClick - */ - bool isBroughtToFrontOnMouseClick() const throw(); + This is a distance in pixels from the top edge of the component's parent. - // Keyboard focus methods + @see getScreenY + */ + inline int getY() const throw() { return bounds_.getY(); } - /** Sets a flag to indicate whether this component needs keyboard focus or not. + /** Returns the component's width in pixels. */ + inline int getWidth() const throw() { return bounds_.getWidth(); } - By default components aren't actually interested in gaining the - focus, but this method can be used to turn this on. + /** Returns the component's height in pixels. */ + inline int getHeight() const throw() { return bounds_.getHeight(); } - See the grabKeyboardFocus() method for details about the way a component - is chosen to receive the focus. + /** Returns the x co-ordinate of the component's right-hand edge. - @see grabKeyboardFocus, getWantsKeyboardFocus + This is a distance in pixels from the left edge of the component's parent. */ - void setWantsKeyboardFocus (const bool wantsFocus) throw(); - - /** Returns true if the component is interested in getting keyboard focus. + int getRight() const throw() { return bounds_.getRight(); } - This returns the flag set by setWantsKeyboardFocus(). The default - setting is false. + /** Returns the y co-ordinate of the bottom edge of this component. - @see setWantsKeyboardFocus + This is a distance in pixels from the top edge of the component's parent. */ - bool getWantsKeyboardFocus() const throw(); + int getBottom() const throw() { return bounds_.getBottom(); } - /** Chooses whether a click on this component automatically grabs the focus. + /** Returns this component's bounding box. - By default this is set to true, but you might want a component which can - be focused, but where you don't want the user to be able to affect it directly - by clicking. + The rectangle returned is relative to the top-left of the component's parent. */ - void setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus); + const Rectangle& getBounds() const throw() { return bounds_; } - /** Returns the last value set with setMouseClickGrabsKeyboardFocus(). + /** Returns the region of this component that's not obscured by other, opaque components. - See setMouseClickGrabsKeyboardFocus() for more info. + The RectangleList that is returned represents the area of this component + which isn't covered by opaque child components. + + If includeSiblings is true, it will also take into account any siblings + that may be overlapping the component. */ - bool getMouseClickGrabsKeyboardFocus() const throw(); + void getVisibleArea (RectangleList& result, + const bool includeSiblings) const; - /** Tries to give keyboard focus to this component. + /** Returns this component's x co-ordinate relative the the screen's top-left origin. - When the user clicks on a component or its grabKeyboardFocus() - method is called, the following procedure is used to work out which - component should get it: - - - if the component that was clicked on actually wants focus (as indicated - by calling getWantsKeyboardFocus), it gets it. - - if the component itself doesn't want focus, it will try to pass it - on to whichever of its children is the default component, as determined by - KeyboardFocusTraverser::getDefaultComponent() - - if none of its children want focus at all, it will pass it up to its - parent instead, unless it's a top-level component without a parent, - in which case it just takes the focus itself. - - @see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus, - getCurrentlyFocusedComponent, focusGained, focusLost, - keyPressed, keyStateChanged + @see getX, relativePositionToGlobal */ - void grabKeyboardFocus(); - - /** Returns true if this component currently has the keyboard focus. + int getScreenX() const throw(); - @param trueIfChildIsFocused if this is true, then the method returns true if - either this component or any of its children (recursively) - have the focus. If false, the method only returns true if - this component has the focus. + /** Returns this component's y co-ordinate relative the the screen's top-left origin. - @see grabKeyboardFocus, setWantsKeyboardFocus, getCurrentlyFocusedComponent, - focusGained, focusLost + @see getY, relativePositionToGlobal */ - bool hasKeyboardFocus (const bool trueIfChildIsFocused) const throw(); + int getScreenY() const throw(); - /** Returns the component that currently has the keyboard focus. + /** Converts a position relative to this component's top-left into a screen co-ordinate. - @returns the focused component, or null if nothing is focused. + @see globalPositionToRelative, relativePositionToOtherComponent */ - static Component* JUCE_CALLTYPE getCurrentlyFocusedComponent() throw(); + void relativePositionToGlobal (int& x, int& y) const throw(); - /** Tries to move the keyboard focus to one of this component's siblings. + /** Converts a screen co-ordinate into a position relative to this component's top-left. - This will try to move focus to either the next or previous component. (This - is the method that is used when shifting focus by pressing the tab key). + @see relativePositionToGlobal, relativePositionToOtherComponent + */ + void globalPositionToRelative (int& x, int& y) const throw(); - Components for which getWantsKeyboardFocus() returns false are not looked at. + /** Converts a position relative to this component's top-left into a position + relative to another component's top-left. - @param moveToNext if true, the focus will move forwards; if false, it will - move backwards - @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus + @see relativePositionToGlobal, globalPositionToRelative */ - void moveKeyboardFocusToSibling (const bool moveToNext); + void relativePositionToOtherComponent (const Component* const targetComponent, + int& x, int& y) const throw(); - /** Creates a KeyboardFocusTraverser object to use to determine the logic by - which focus should be passed from this component. + /** Moves the component to a new position. - The default implementation of this method will return a default - KeyboardFocusTraverser if this component is a focus container (as determined - by the setFocusContainer() method). If the component isn't a focus - container, then it will recursively ask its parents for a KeyboardFocusTraverser. + Changes the component's top-left position (without changing its size). + The position is relative to the top-left of the component's parent. - If you overrride this to return a custom KeyboardFocusTraverser, then - this component and all its sub-components will use the new object to - make their focusing decisions. + If the component actually moves, this method will make a synchronous call to moved(). - The method should return a new object, which the caller is required to - delete when no longer needed. + @see setBounds, ComponentListener::componentMovedOrResized */ - virtual KeyboardFocusTraverser* createFocusTraverser(); - - /** Returns the focus order of this component, if one has been specified. - - By default components don't have a focus order - in that case, this - will return 0. Lower numbers indicate that the component will be - earlier in the focus traversal order. + void setTopLeftPosition (const int x, const int y); - To change the order, call setExplicitFocusOrder(). + /** Moves the component to a new position. - The focus order may be used by the KeyboardFocusTraverser class as part of - its algorithm for deciding the order in which components should be traversed. - See the KeyboardFocusTraverser class for more details on this. + Changes the position of the component's top-right corner (keeping it the same size). + The position is relative to the top-left of the component's parent. - @see moveKeyboardFocusToSibling, createFocusTraverser, KeyboardFocusTraverser + If the component actually moves, this method will make a synchronous call to moved(). */ - int getExplicitFocusOrder() const throw(); - - /** Sets the index used in determining the order in which focusable components - should be traversed. + void setTopRightPosition (const int x, const int y); - A value of 0 or less is taken to mean that no explicit order is wanted, and - that traversal should use other factors, like the component's position. + /** Changes the size of the component. - @see getExplicitFocusOrder, moveKeyboardFocusToSibling + A synchronous call to resized() will be occur if the size actually changes. */ - void setExplicitFocusOrder (const int newFocusOrderIndex) throw(); + void setSize (const int newWidth, const int newHeight); - /** Indicates whether this component is a parent for components that can have - their focus traversed. + /** Changes the component's position and size. - This flag is used by the default implementation of the createFocusTraverser() - method, which uses the flag to find the first parent component (of the currently - focused one) which wants to be a focus container. + The co-ordinates are relative to the top-left of the component's parent, or relative + to the origin of the screen is the component is on the desktop. - So using this method to set the flag to 'true' causes this component to - act as the top level within which focus is passed around. + If this method changes the component's top-left position, it will make a synchronous + call to moved(). If it changes the size, it will also make a call to resized(). - @see isFocusContainer, createFocusTraverser, moveKeyboardFocusToSibling + @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized */ - void setFocusContainer (const bool shouldBeFocusContainer) throw(); - - /** Returns true if this component has been marked as a focus container. + void setBounds (int x, int y, int width, int height); - See setFocusContainer() for more details. + /** Changes the component's position and size. - @see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser + @see setBounds */ - bool isFocusContainer() const throw(); + void setBounds (const Rectangle& newBounds); - /** Returns true if the component (and all its parents) are enabled. + /** Changes the component's position and size in terms of fractions of its parent's size. - Components are enabled by default, and can be disabled with setEnabled(). Exactly - what difference this makes to the component depends on the type. E.g. buttons - and sliders will choose to draw themselves differently, etc. + The values are factors of the parent's size, so for example + setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the + width and height of the parent, with its top-left position 20% of + the way across and down the parent. + */ + void setBoundsRelative (const float proportionalX, const float proportionalY, + const float proportionalWidth, const float proportionalHeight); - Note that if one of this component's parents is disabled, this will always - return false, even if this component itself is enabled. + /** Changes the component's position and size based on the amount of space to leave around it. - @see setEnabled, enablementChanged + This will position the component within its parent, leaving the specified number of + pixels around each edge. */ - bool isEnabled() const throw(); - - /** Enables or disables this component. + void setBoundsInset (const BorderSize& borders); - Disabling a component will also cause all of its child components to become - disabled. + /** Positions the component within a given rectangle, keeping its proportions + unchanged. - Similarly, enabling a component which is inside a disabled parent - component won't make any difference until the parent is re-enabled. + If onlyReduceInSize is false, the component will be resized to fill as much of the + rectangle as possible without changing its aspect ratio (the component's + current size is used to determine its aspect ratio, so a zero-size component + won't work here). If onlyReduceInSize is true, it will only be resized if it's + too big to fit inside the rectangle. - @see isEnabled, enablementChanged + It will then be positioned within the rectangle according to the justification flags + specified. */ - void setEnabled (const bool shouldBeEnabled); + void setBoundsToFit (int x, int y, int width, int height, + const Justification& justification, + const bool onlyReduceInSize); - /** Callback to indicate that this component has been enabled or disabled. + /** Changes the position of the component's centre. - This can be triggered by one of the component's parent components - being enabled or disabled, as well as changes to the component itself. + Leaves the component's size unchanged, but sets the position of its centre + relative to its parent's top-left. + */ + void setCentrePosition (const int x, const int y); - The default implementation of this method does nothing; your class may - wish to repaint itself or something when this happens. + /** Changes the position of the component's centre. - @see setEnabled, isEnabled + Leaves the position unchanged, but positions its centre relative to its + parent's size. E.g. setCentreRelative (0.5f, 0.5f) would place it centrally in + its parent. */ - virtual void enablementChanged(); - - /** Changes the mouse cursor shape to use when the mouse is over this component. + void setCentreRelative (const float x, const float y); - Note that the cursor set by this method can be overridden by the getMouseCursor - method. + /** Changes the component's size and centres it within its parent. - @see MouseCursor + After changing the size, the component will be moved so that it's + centred within its parent. */ - void setMouseCursor (const MouseCursor& cursorType) throw(); - - /** Returns the mouse cursor shape to use when the mouse is over this component. + void centreWithSize (const int width, const int height); - The default implementation will return the cursor that was set by setCursor() - but can be overridden for more specialised purposes, e.g. returning different - cursors depending on the mouse position. + /** Returns a proportion of the component's width. - @see MouseCursor + This is a handy equivalent of (getWidth() * proportion). */ - virtual const MouseCursor getMouseCursor(); - - /** Forces the current mouse cursor to be updated. + int proportionOfWidth (const float proportion) const throw(); - If you're overriding the getMouseCursor() method to control which cursor is - displayed, then this will only be checked each time the user moves the mouse. So - if you want to force the system to check that the cursor being displayed is - up-to-date (even if the mouse is just sitting there), call this method. + /** Returns a proportion of the component's height. - This isn't needed if you're only using setMouseCursor(). + This is a handy equivalent of (getHeight() * proportion). */ - void updateMouseCursor() const throw(); + int proportionOfHeight (const float proportion) const throw(); - /** Components can override this method to draw their content. + /** Returns the width of the component's parent. - The paint() method gets called when a region of a component needs redrawing, - either because the component's repaint() method has been called, or because - something has happened on the screen that means a section of a window needs - to be redrawn. + If the component has no parent (i.e. if it's on the desktop), this will return + the width of the screen. + */ + int getParentWidth() const throw(); - Any child components will draw themselves over whatever this method draws. If - you need to paint over the top of your child components, you can also implement - the paintOverChildren() method to do this. + /** Returns the height of the component's parent. - If you want to cause a component to redraw itself, this is done asynchronously - - calling the repaint() method marks a region of the component as "dirty", and the - paint() method will automatically be called sometime later, by the message thread, - to paint any bits that need refreshing. In Juce (and almost all modern UI frameworks), - you never redraw something synchronously. + If the component has no parent (i.e. if it's on the desktop), this will return + the height of the screen. + */ + int getParentHeight() const throw(); - You should never need to call this method directly - to take a snapshot of the - component you could use createComponentSnapshot() or paintEntireComponent(). + /** Returns the screen co-ordinates of the monitor that contains this component. - @param g the graphics context that must be used to do the drawing operations. - @see repaint, paintOverChildren, Graphics + If there's only one monitor, this will return its size - if there are multiple + monitors, it will return the area of the monitor that contains the component's + centre. */ - virtual void paint (Graphics& g); - - /** Components can override this method to draw over the top of their children. + const Rectangle getParentMonitorArea() const throw(); - For most drawing operations, it's better to use the normal paint() method, - but if you need to overlay something on top of the children, this can be - used. + /** Returns the number of child components that this component contains. - @see paint, Graphics + @see getChildComponent, getIndexOfChildComponent */ - virtual void paintOverChildren (Graphics& g); + int getNumChildComponents() const throw(); - /** Called when the mouse moves inside this component. + /** Returns one of this component's child components, by it index. - If the mouse button isn't pressed and the mouse moves over a component, - this will be called to let the component react to this. + The component with index 0 is at the back of the z-order, the one at the + front will have index (getNumChildComponents() - 1). - A component will always get a mouseEnter callback before a mouseMove. + If the index is out-of-range, this will return a null pointer. - @param e details about the position and status of the mouse event - @see mouseEnter, mouseExit, mouseDrag, contains + @see getNumChildComponents, getIndexOfChildComponent */ - virtual void mouseMove (const MouseEvent& e); - - /** Called when the mouse first enters this component. + Component* getChildComponent (const int index) const throw(); - If the mouse button isn't pressed and the mouse moves into a component, - this will be called to let the component react to this. + /** Returns the index of this component in the list of child components. - When the mouse button is pressed and held down while being moved in - or out of a component, no mouseEnter or mouseExit callbacks are made - only - mouseDrag messages are sent to the component that the mouse was originally - clicked on, until the button is released. + A value of 0 means it is first in the list (i.e. behind all other components). Higher + values are further towards the front. - If you're writing a component that needs to repaint itself when the mouse - enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() - method. + Returns -1 if the component passed-in is not a child of this component. - @param e details about the position and status of the mouse event - @see mouseExit, mouseDrag, mouseMove, contains + @see getNumChildComponents, getChildComponent, addChildComponent, toFront, toBack, toBehind */ - virtual void mouseEnter (const MouseEvent& e); + int getIndexOfChildComponent (const Component* const child) const throw(); - /** Called when the mouse moves out of this component. + /** Adds a child component to this one. - This will be called when the mouse moves off the edge of this - component. + @param child the new component to add. If the component passed-in is already + the child of another component, it'll first be removed from that. - If the mouse button was pressed, and it was then dragged off the - edge of the component and released, then this callback will happen - when the button is released, after the mouseUp callback. + @param zOrder The index in the child-list at which this component should be inserted. + A value of -1 will insert it in front of the others, 0 is the back. + @see removeChildComponent, addAndMakeVisible, getChild, + ComponentListener::componentChildrenChanged + */ + void addChildComponent (Component* const child, + int zOrder = -1); - If you're writing a component that needs to repaint itself when the mouse - enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() - method. + /** Adds a child component to this one, and also makes the child visible if it isn't. - @param e details about the position and status of the mouse event - @see mouseEnter, mouseDrag, mouseMove, contains + Quite a useful function, this is just the same as calling addChildComponent() + followed by setVisible (true) on the child. */ - virtual void mouseExit (const MouseEvent& e); + void addAndMakeVisible (Component* const child, + int zOrder = -1); - /** Called when a mouse button is pressed while it's over this component. + /** Removes one of this component's child-components. - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. + If the child passed-in isn't actually a child of this component (either because + it's invalid or is the child of a different parent), then nothing is done. - Once a button is held down, the mouseDrag method will be called when the - mouse moves, until the button is released. + Note that removing a child will not delete it! - @param e details about the position and status of the mouse event - @see mouseUp, mouseDrag, mouseDoubleClick, contains + @see addChildComponent, ComponentListener::componentChildrenChanged */ - virtual void mouseDown (const MouseEvent& e); + void removeChildComponent (Component* const childToRemove); - /** Called when the mouse is moved while a button is held down. + /** Removes one of this component's child-components by index. - When a mouse button is pressed inside a component, that component - receives mouseDrag callbacks each time the mouse moves, even if the - mouse strays outside the component's bounds. + This will return a pointer to the component that was removed, or null if + the index was out-of-range. - If you want to be able to drag things off the edge of a component - and have the component scroll when you get to the edges, the - beginDragAutoRepeat() method might be useful. + Note that removing a child will not delete it! - @param e details about the position and status of the mouse event - @see mouseDown, mouseUp, mouseMove, contains, beginDragAutoRepeat + @see addChildComponent, ComponentListener::componentChildrenChanged */ - virtual void mouseDrag (const MouseEvent& e); - - /** Called when a mouse button is released. - - A mouseUp callback is sent to the component in which a button was pressed - even if the mouse is actually over a different component when the - button is released. + Component* removeChildComponent (const int childIndexToRemove); - The MouseEvent object passed in contains lots of methods for finding out - which buttons were down just before they were released. + /** Removes all this component's children. - @param e details about the position and status of the mouse event - @see mouseDown, mouseDrag, mouseDoubleClick, contains + Note that this won't delete them! To do that, use deleteAllChildren() instead. */ - virtual void mouseUp (const MouseEvent& e); + void removeAllChildren(); - /** Called when a mouse button has been double-clicked in this component. + /** Removes all this component's children, and deletes them. - The MouseEvent object passed in contains lots of methods for finding out - which button was pressed, as well as which modifier keys (e.g. shift, ctrl) - were held down at the time. + @see removeAllChildren + */ + void deleteAllChildren(); - For altering the time limit used to detect double-clicks, - see MouseEvent::setDoubleClickTimeout. + /** Returns the component which this component is inside. - @param e details about the position and status of the mouse event - @see mouseDown, mouseUp, MouseEvent::setDoubleClickTimeout, - MouseEvent::getDoubleClickTimeout + If this is the highest-level component or hasn't yet been added to + a parent, this will return null. */ - virtual void mouseDoubleClick (const MouseEvent& e); - - /** Called when the mouse-wheel is moved. + Component* getParentComponent() const throw() { return parentComponent_; } - This callback is sent to the component that the mouse is over when the - wheel is moved. + /** Searches the parent components for a component of a specified class. - If not overridden, the component will forward this message to its parent, so - that parent components can collect mouse-wheel messages that happen to - child components which aren't interested in them. + For example findParentComponentOfClass \() would return the first parent + component that can be dynamically cast to a MyComp, or will return 0 if none + of the parents are suitable. - @param e details about the position and status of the mouse event - @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive - value means the wheel has been pushed to the right, negative means it - was pushed to the left - @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive - value means the wheel has been pushed upwards, negative means it - was pushed downwards + N.B. The dummy parameter is needed to work around a VC6 compiler bug. */ - virtual void mouseWheelMove (const MouseEvent& e, - float wheelIncrementX, - float wheelIncrementY); - - /** Ensures that a non-stop stream of mouse-drag events will be sent during the - next mouse-drag operation. + template + TargetClass* findParentComponentOfClass (TargetClass* const dummyParameter = 0) const + { + (void) dummyParameter; + Component* p = parentComponent_; + while (p != 0) + { + TargetClass* target = dynamic_cast (p); + if (target != 0) + return target; - This allows you to make sure that mouseDrag() events sent continuously, even - when the mouse isn't moving. This can be useful for things like auto-scrolling - components when the mouse is near an edge. + p = p->parentComponent_; + } - Call this method during a mouseDown() or mouseDrag() callback, specifying the - minimum interval between consecutive mouse drag callbacks. The callbacks - will continue until the mouse is released, and then the interval will be reset, - so you need to make sure it's called every time you begin a drag event. If it - is called when the mouse isn't actually being pressed, it will apply to the next - mouse-drag operation that happens. + return 0; + } - Passing an interval of 0 or less will cancel the auto-repeat. + /** Returns the highest-level component which contains this one or its parents. - @see mouseDrag + This will search upwards in the parent-hierarchy from this component, until it + finds the highest one that doesn't have a parent (i.e. is on the desktop or + not yet added to a parent), and will return that. */ - static void beginDragAutoRepeat (const int millisecondIntervalBetweenCallbacks); - - /** Causes automatic repaints when the mouse enters or exits this component. - - If turned on, then when the mouse enters/exits, or when the button is pressed/released - on the component, it will trigger a repaint. + Component* getTopLevelComponent() const throw(); - This is handy for things like buttons that need to draw themselves differently when - the mouse moves over them, and it avoids having to override all the different mouse - callbacks and call repaint(). + /** Checks whether a component is anywhere inside this component or its children. - @see mouseEnter, mouseExit, mouseDown, mouseUp + This will recursively check through this components children to see if the + given component is anywhere inside. */ - void setRepaintsOnMouseActivity (const bool shouldRepaint) throw(); + bool isParentOf (const Component* possibleChild) const throw(); - /** Registers a listener to be told when mouse events occur in this component. + /** Called to indicate that the component's parents have changed. - If you need to get informed about mouse events in a component but can't or - don't want to override its methods, you can attach any number of listeners - to the component, and these will get told about the events in addition to - the component's own callbacks being called. + When a component is added or removed from its parent, this method will + be called on all of its children (recursively - so all children of its + children will also be called as well). - Note that a MouseListener can also be attached to more than one component. + Subclasses can override this if they need to react to this in some way. - @param newListener the listener to register - @param wantsEventsForAllNestedChildComponents if true, the listener will receive callbacks - for events that happen to any child component - within this component, including deeply-nested - child components. If false, it will only be - told about events that this component handles. - @see MouseListener, removeMouseListener + @see getParentComponent, isShowing, ComponentListener::componentParentHierarchyChanged */ - void addMouseListener (MouseListener* const newListener, - const bool wantsEventsForAllNestedChildComponents) throw(); + virtual void parentHierarchyChanged(); - /** Deregisters a mouse listener. + /** Subclasses can use this callback to be told when children are added or removed. - @see addMouseListener, MouseListener + @see parentHierarchyChanged */ - void removeMouseListener (MouseListener* const listenerToRemove) throw(); + virtual void childrenChanged(); - /** Adds a listener that wants to hear about keypresses that this component receives. + /** Tests whether a given point inside the component. - The listeners that are registered with a component are called by its keyPressed() or - keyStateChanged() methods (assuming these haven't been overridden to do something else). + Overriding this method allows you to create components which only intercept + mouse-clicks within a user-defined area. - If you add an object as a key listener, be careful to remove it when the object - is deleted, or the component will be left with a dangling pointer. + This is called to find out whether a particular x, y co-ordinate is + considered to be inside the component or not, and is used by methods such + as contains() and getComponentAt() to work out which component + the mouse is clicked on. - @see keyPressed, keyStateChanged, removeKeyListener - */ - void addKeyListener (KeyListener* const newListener) throw(); + Components with custom shapes will probably want to override it to perform + some more complex hit-testing. - /** Removes a previously-registered key listener. + The default implementation of this method returns either true or false, + depending on the value that was set by calling setInterceptsMouseClicks() (true + is the default return value). - @see addKeyListener - */ - void removeKeyListener (KeyListener* const listenerToRemove) throw(); + Note that the hit-test region is not related to the opacity with which + areas of a component are painted. - /** Called when a key is pressed. + Applications should never call hitTest() directly - instead use the + contains() method, because this will also test for occlusion by the + component's parent. - When a key is pressed, the component that has the keyboard focus will have this - method called. Remember that a component will only be given the focus if its - setWantsKeyboardFocus() method has been used to enable this. + Note that for components on the desktop, this method will be ignored, because it's + not always possible to implement this behaviour on all platforms. - If your implementation returns true, the event will be consumed and not passed - on to any other listeners. If it returns false, the key will be passed to any - KeyListeners that have been registered with this component. As soon as one of these - returns true, the process will stop, but if they all return false, the event will - be passed upwards to this component's parent, and so on. - - The default implementation of this method does nothing and returns false. - - @see keyStateChanged, getCurrentlyFocusedComponent, addKeyListener + @param x the x co-ordinate to test, relative to the left hand edge of this + component. This value is guaranteed to be greater than or equal to + zero, and less than the component's width + @param y the y co-ordinate to test, relative to the top edge of this + component. This value is guaranteed to be greater than or equal to + zero, and less than the component's height + @returns true if the click is considered to be inside the component + @see setInterceptsMouseClicks, contains */ - virtual bool keyPressed (const KeyPress& key); + virtual bool hitTest (int x, int y); - /** Called when a key is pressed or released. + /** Changes the default return value for the hitTest() method. - Whenever a key on the keyboard is pressed or released (including modifier keys - like shift and ctrl), this method will be called on the component that currently - has the keyboard focus. Remember that a component will only be given the focus if - its setWantsKeyboardFocus() method has been used to enable this. + Setting this to false is an easy way to make a component pass its mouse-clicks + through to the components behind it. - If your implementation returns true, the event will be consumed and not passed - on to any other listeners. If it returns false, then any KeyListeners that have - been registered with this component will have their keyStateChanged methods called. - As soon as one of these returns true, the process will stop, but if they all return - false, the event will be passed upwards to this component's parent, and so on. + When a component is created, the default setting for this is true. - The default implementation of this method does nothing and returns false. + @param allowClicksOnThisComponent if true, hitTest() will always return true; if false, it will + return false (or true for child components if allowClicksOnChildComponents + is true) + @param allowClicksOnChildComponents if this is true and allowClicksOnThisComponent is false, then child + components can be clicked on as normal but clicks on this component pass + straight through; if this is false and allowClicksOnThisComponent + is false, then neither this component nor any child components can + be clicked on + @see hitTest, getInterceptsMouseClicks + */ + void setInterceptsMouseClicks (const bool allowClicksOnThisComponent, + const bool allowClicksOnChildComponents) throw(); - To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() - method. + /** Retrieves the current state of the mouse-click interception flags. - @param isKeyDown true if a key has been pressed; false if it has been released + On return, the two parameters are set to the state used in the last call to + setInterceptsMouseClicks(). - @see keyPressed, KeyPress, getCurrentlyFocusedComponent, addKeyListener + @see setInterceptsMouseClicks */ - virtual bool keyStateChanged (const bool isKeyDown); - - /** Called when a modifier key is pressed or released. + void getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, + bool& allowsClicksOnChildComponents) const throw(); - Whenever the shift, control, alt or command keys are pressed or released, - this method will be called on the component that currently has the keyboard focus. - Remember that a component will only be given the focus if its setWantsKeyboardFocus() - method has been used to enable this. + /** Returns true if a given point lies within this component or one of its children. - The default implementation of this method actually calls its parent's modifierKeysChanged - method, so that focused components which aren't interested in this will give their - parents a chance to act on the event instead. + Never override this method! Use hitTest to create custom hit regions. - @see keyStateChanged, ModifierKeys + @param x the x co-ordinate to test, relative to this component's left hand edge. + @param y the y co-ordinate to test, relative to this component's top edge. + @returns true if the point is within the component's hit-test area, but only if + that part of the component isn't clipped by its parent component. Note + that this won't take into account any overlapping sibling components + which might be in the way - for that, see reallyContains() + @see hitTest, reallyContains, getComponentAt */ - virtual void modifierKeysChanged (const ModifierKeys& modifiers); + virtual bool contains (int x, int y); - /** Enumeration used by the focusChanged() and focusLost() methods. */ - enum FocusChangeType - { - focusChangedByMouseClick, /**< Means that the user clicked the mouse to change focus. */ - focusChangedByTabKey, /**< Means that the user pressed the tab key to move the focus. */ - focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */ - }; + /** Returns true if a given point lies in this component, taking any overlapping + siblings into account. - /** Called to indicate that this component has just acquired the keyboard focus. + @param x the x co-ordinate to test, relative to this component's left hand edge. + @param y the y co-ordinate to test, relative to this component's top edge. + @param returnTrueIfWithinAChild if the point actually lies within a child of this + component, this determines the value that will + be returned. - @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + @see contains, getComponentAt */ - virtual void focusGained (FocusChangeType cause); + bool reallyContains (int x, int y, + const bool returnTrueIfWithinAChild); - /** Called to indicate that this component has just lost the keyboard focus. + /** Returns the component at a certain point within this one. - @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + @param x the x co-ordinate to test, relative to this component's left hand edge. + @param y the y co-ordinate to test, relative to this component's top edge. + @returns the component that is at this position - which may be 0, this component, + or one of its children. Note that overlapping siblings that might actually + be in the way are not taken into account by this method - to account for these, + instead call getComponentAt on the top-level parent of this component. + @see hitTest, contains, reallyContains */ - virtual void focusLost (FocusChangeType cause); + Component* getComponentAt (const int x, const int y); - /** Called to indicate that one of this component's children has been focused or unfocused. + /** Marks the whole component as needing to be redrawn. - Essentially this means that the return value of a call to hasKeyboardFocus (true) has - changed. It happens when focus moves from one of this component's children (at any depth) - to a component that isn't contained in this one, (or vice-versa). + Calling this will not do any repainting immediately, but will mark the component + as 'dirty'. At some point in the near future the operating system will send a paint + message, which will redraw all the dirty regions of all components. + There's no guarantee about how soon after calling repaint() the redraw will actually + happen, and other queued events may be delivered before a redraw is done. - @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + If the setBufferedToImage() method has been used to cause this component + to use a buffer, the repaint() call will invalidate the component's buffer. + + To redraw just a subsection of the component rather than the whole thing, + use the repaint (int, int, int, int) method. + + @see paint */ - virtual void focusOfChildComponentChanged (FocusChangeType cause); + void repaint() throw(); - /** Returns true if the mouse is currently over this component. + /** Marks a subsection of this component as needing to be redrawn. - If the mouse isn't over the component, this will return false, even if the - mouse is currently being dragged - so you can use this in your mouseDrag - method to find out whether it's really over the component or not. + Calling this will not do any repainting immediately, but will mark the given region + of the component as 'dirty'. At some point in the near future the operating system + will send a paint message, which will redraw all the dirty regions of all components. + There's no guarantee about how soon after calling repaint() the redraw will actually + happen, and other queued events may be delivered before a redraw is done. - Note that when the mouse button is being held down, then the only component - for which this method will return true is the one that was originally - clicked on. + The region that is passed in will be clipped to keep it within the bounds of this + component. - @see isMouseButtonDown. isMouseOverOrDragging, mouseDrag + @see repaint() */ - bool isMouseOver() const throw(); + void repaint (const int x, const int y, + const int width, const int height) throw(); - /** Returns true if the mouse button is currently held down in this component. + /** Makes the component use an internal buffer to optimise its redrawing. - Note that this is a test to see whether the mouse is being pressed in this - component, so it'll return false if called on component A when the mouse - is actually being dragged in component B. + Setting this flag to true will cause the component to allocate an + internal buffer into which it paints itself, so that when asked to + redraw itself, it can use this buffer rather than actually calling the + paint() method. - @see isMouseButtonDownAnywhere, isMouseOver, isMouseOverOrDragging + The buffer is kept until the repaint() method is called directly on + this component (or until it is resized), when the image is invalidated + and then redrawn the next time the component is painted. + + Note that only the drawing that happens within the component's paint() + method is drawn into the buffer, it's child components are not buffered, and + nor is the paintOverChildren() method. + + @see repaint, paint, createComponentSnapshot */ - bool isMouseButtonDown() const throw(); + void setBufferedToImage (const bool shouldBeBuffered) throw(); - /** True if the mouse is over this component, or if it's being dragged in this component. + /** Generates a snapshot of part of this component. - This is a handy equivalent to (isMouseOver() || isMouseButtonDown()). + This will return a new Image, the size of the rectangle specified, + containing a snapshot of the specified area of the component and all + its children. - @see isMouseOver, isMouseButtonDown, isMouseButtonDownAnywhere - */ - bool isMouseOverOrDragging() const throw(); + The image may or may not have an alpha-channel, depending on whether the + image is opaque or not. - /** Returns true if a mouse button is currently down. + If the clipImageToComponentBounds parameter is true and the area is greater than + the size of the component, it'll be clipped. If clipImageToComponentBounds is false + then parts of the component beyond its bounds can be drawn. - Unlike isMouseButtonDown, this will test the current state of the - buttons without regard to which component (if any) it has been - pressed in. + The caller is responsible for deleting the image that is returned. - @see isMouseButtonDown, ModifierKeys + @see paintEntireComponent */ - static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw(); + Image* createComponentSnapshot (const Rectangle& areaToGrab, + const bool clipImageToComponentBounds = true); - /** Returns the mouse's current position, relative to this component. + /** Draws this component and all its subcomponents onto the specified graphics + context. - The co-ordinates are relative to the component's top-left corner. - */ - void getMouseXYRelative (int& x, int& y) const throw(); + You should very rarely have to use this method, it's simply there in case you need + to draw a component with a custom graphics context for some reason, e.g. for + creating a snapshot of the component. - /** Returns the component that's currently underneath the mouse. + It calls paint(), paintOverChildren() and recursively calls paintEntireComponent() + on its children in order to render the entire tree. - @returns the component or 0 if there isn't one. - @see contains, getComponentAt + The graphics context may be left in an undefined state after this method returns, + so you may need to reset it if you're going to use it again. */ - static Component* JUCE_CALLTYPE getComponentUnderMouse() throw(); + void paintEntireComponent (Graphics& context); - /** Allows the mouse to move beyond the edges of the screen. + /** Adds an effect filter to alter the component's appearance. - Calling this method when the mouse button is currently pressed inside this component - will remove the cursor from the screen and allow the mouse to (seem to) move beyond - the edges of the screen. + When a component has an effect filter set, then this is applied to the + results of its paint() method. There are a few preset effects, such as + a drop-shadow or glow, but they can be user-defined as well. - This means that the co-ordinates returned to mouseDrag() will be unbounded, and this - can be used for things like custom slider controls or dragging objects around, where - movement would be otherwise be limited by the mouse hitting the edges of the screen. + The effect that is passed in will not be deleted by the component - the + caller must take care of deleting it. - The unbounded mode is automatically turned off when the mouse button is released, or - it can be turned off explicitly by calling this method again. + To remove an effect from a component, pass a null pointer in as the parameter. - @param shouldUnboundedMovementBeEnabled whether to turn this mode on or off - @param keepCursorVisibleUntilOffscreen if set to false, the cursor will immediately be - hidden; if true, it will only be hidden when it - is moved beyond the edge of the screen + @see ImageEffectFilter, DropShadowEffect, GlowEffect */ - void enableUnboundedMouseMovement (bool shouldUnboundedMovementBeEnabled, - bool keepCursorVisibleUntilOffscreen = false) throw(); + void setComponentEffect (ImageEffectFilter* const newEffect); - /** Called when this component's size has been changed. + /** Returns the current component effect. - A component can implement this method to do things such as laying out its - child components when its width or height changes. + @see setComponentEffect + */ + ImageEffectFilter* getComponentEffect() const throw() { return effect_; } - The method is called synchronously as a result of the setBounds or setSize - methods, so repeatedly changing a components size will repeatedly call its - resized method (unlike things like repainting, where multiple calls to repaint - are coalesced together). + /** Finds the appropriate look-and-feel to use for this component. - If the component is a top-level window on the desktop, its size could also - be changed by operating-system factors beyond the application's control. + If the component hasn't had a look-and-feel explicitly set, this will + return the parent's look-and-feel, or just the default one if there's no + parent. - @see moved, setSize + @see setLookAndFeel, lookAndFeelChanged */ - virtual void resized(); + LookAndFeel& getLookAndFeel() const throw(); - /** Called when this component's position has been changed. + /** Sets the look and feel to use for this component. - This is called when the position relative to its parent changes, not when - its absolute position on the screen changes (so it won't be called for - all child components when a parent component is moved). + This will also change the look and feel for any child components that haven't + had their look set explicitly. - The method is called synchronously as a result of the setBounds, setTopLeftPosition - or any of the other repositioning methods, and like resized(), it will be - called each time those methods are called. + The object passed in will not be deleted by the component, so it's the caller's + responsibility to manage it. It may be used at any time until this component + has been deleted. - If the component is a top-level window on the desktop, its position could also - be changed by operating-system factors beyond the application's control. + Calling this method will also invoke the sendLookAndFeelChange() method. - @see resized, setBounds + @see getLookAndFeel, lookAndFeelChanged */ - virtual void moved(); + void setLookAndFeel (LookAndFeel* const newLookAndFeel); - /** Called when one of this component's children is moved or resized. + /** Called to let the component react to a change in the look-and-feel setting. - If the parent wants to know about changes to its immediate children (not - to children of its children), this is the method to override. + When the look-and-feel is changed for a component, this will be called in + all its child components, recursively. - @see moved, resized, parentSizeChanged + It can also be triggered manually by the sendLookAndFeelChange() method, in case + an application uses a LookAndFeel class that might have changed internally. + + @see sendLookAndFeelChange, getLookAndFeel */ - virtual void childBoundsChanged (Component* child); + virtual void lookAndFeelChanged(); - /** Called when this component's immediate parent has been resized. + /** Calls the lookAndFeelChanged() method in this component and all its children. - If the component is a top-level window, this indicates that the screen size - has changed. + This will recurse through the children and their children, calling lookAndFeelChanged() + on them all. - @see childBoundsChanged, moved, resized + @see lookAndFeelChanged */ - virtual void parentSizeChanged(); - - /** Called when this component has been moved to the front of its siblings. + void sendLookAndFeelChange(); - The component may have been brought to the front by the toFront() method, or - by the operating system if it's a top-level window. + /** Indicates whether any parts of the component might be transparent. - @see toFront - */ - virtual void broughtToFront(); + Components that always paint all of their contents with solid colour and + thus completely cover any components behind them should use this method + to tell the repaint system that they are opaque. - /** Adds a listener to be told about changes to the component hierarchy or position. + This information is used to optimise drawing, because it means that + objects underneath opaque windows don't need to be painted. - Component listeners get called when this component's size, position or children - change - see the ComponentListener class for more details. + By default, components are considered transparent, unless this is used to + make it otherwise. - @param newListener the listener to register - if this is already registered, it - will be ignored. - @see ComponentListener, removeComponentListener + @see isOpaque, getVisibleArea */ - void addComponentListener (ComponentListener* const newListener) throw(); + void setOpaque (const bool shouldBeOpaque) throw(); - /** Removes a component listener. + /** Returns true if no parts of this component are transparent. - @see addComponentListener + @returns the value that was set by setOpaque, (the default being false) + @see setOpaque */ - void removeComponentListener (ComponentListener* const listenerToRemove) throw(); + bool isOpaque() const throw(); - /** Dispatches a numbered message to this component. + /** Indicates whether the component should be brought to the front when clicked. - This is a quick and cheap way of allowing simple asynchronous messages to - be sent to components. It's also safe, because if the component that you - send the message to is a null or dangling pointer, this won't cause an error. + Setting this flag to true will cause the component to be brought to the front + when the mouse is clicked somewhere inside it or its child components. - The command ID is later delivered to the component's handleCommandMessage() method by - the application's message queue. + Note that a top-level desktop window might still be brought to the front by the + operating system when it's clicked, depending on how the OS works. - @see handleCommandMessage - */ - void postCommandMessage (const int commandId) throw(); + By default this is set to false. - /** Called to handle a command that was sent by postCommandMessage(). + @see setMouseClickGrabsKeyboardFocus + */ + void setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) throw(); - This is called by the message thread when a command message arrives, and - the component can override this method to process it in any way it needs to. + /** Indicates whether the component should be brought to the front when clicked-on. - @see postCommandMessage + @see setBroughtToFrontOnMouseClick */ - virtual void handleCommandMessage (int commandId); + bool isBroughtToFrontOnMouseClick() const throw(); - /** Runs a component modally, waiting until the loop terminates. + // Keyboard focus methods - This method first makes the component visible, brings it to the front and - gives it the keyboard focus. + /** Sets a flag to indicate whether this component needs keyboard focus or not. - It then runs a loop, dispatching messages from the system message queue, but - blocking all mouse or keyboard messages from reaching any components other - than this one and its children. + By default components aren't actually interested in gaining the + focus, but this method can be used to turn this on. - This loop continues until the component's exitModalState() method is called (or - the component is deleted), and then this method returns, returning the value - passed into exitModalState(). + See the grabKeyboardFocus() method for details about the way a component + is chosen to receive the focus. - @see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent, - isCurrentlyBlockedByAnotherModalComponent, MessageManager::dispatchNextMessage + @see grabKeyboardFocus, getWantsKeyboardFocus */ - int runModalLoop(); - - /** Puts the component into a modal state. + void setWantsKeyboardFocus (const bool wantsFocus) throw(); - This makes the component modal, so that messages are blocked from reaching - any components other than this one and its children, but unlike runModalLoop(), - this method returns immediately. + /** Returns true if the component is interested in getting keyboard focus. - If takeKeyboardFocus is true, the component will use grabKeyboardFocus() to - get the focus, which is usually what you'll want it to do. If not, it will leave - the focus unchanged. + This returns the flag set by setWantsKeyboardFocus(). The default + setting is false. - @see exitModalState, runModalLoop + @see setWantsKeyboardFocus */ - void enterModalState (const bool takeKeyboardFocus = true); - - /** Ends a component's modal state. + bool getWantsKeyboardFocus() const throw(); - If this component is currently modal, this will turn of its modalness, and return - a value to the runModalLoop() method that might have be running its modal loop. + /** Chooses whether a click on this component automatically grabs the focus. - @see runModalLoop, enterModalState, isCurrentlyModal + By default this is set to true, but you might want a component which can + be focused, but where you don't want the user to be able to affect it directly + by clicking. */ - void exitModalState (const int returnValue); - - /** Returns true if this component is the modal one. + void setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus); - It's possible to have nested modal components, e.g. a pop-up dialog box - that launches another pop-up, but this will only return true for - the one at the top of the stack. + /** Returns the last value set with setMouseClickGrabsKeyboardFocus(). - @see getCurrentlyModalComponent + See setMouseClickGrabsKeyboardFocus() for more info. */ - bool isCurrentlyModal() const throw(); + bool getMouseClickGrabsKeyboardFocus() const throw(); - /** Returns the number of components that are currently in a modal state. - @see getCurrentlyModalComponent - */ - static int JUCE_CALLTYPE getNumCurrentlyModalComponents() throw(); + /** Tries to give keyboard focus to this component. - /** Returns one of the components that are currently modal. + When the user clicks on a component or its grabKeyboardFocus() + method is called, the following procedure is used to work out which + component should get it: - The index specifies which of the possible modal components to return. The order - of the components in this list is the reverse of the order in which they became - modal - so the component at index 0 is always the active component, and the others - are progressively earlier ones that are themselves now blocked by later ones. + - if the component that was clicked on actually wants focus (as indicated + by calling getWantsKeyboardFocus), it gets it. + - if the component itself doesn't want focus, it will try to pass it + on to whichever of its children is the default component, as determined by + KeyboardFocusTraverser::getDefaultComponent() + - if none of its children want focus at all, it will pass it up to its + parent instead, unless it's a top-level component without a parent, + in which case it just takes the focus itself. - @returns the modal component, or null if no components are modal (or if the - index is out of range) - @see getNumCurrentlyModalComponents, runModalLoop, isCurrentlyModal + @see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus, + getCurrentlyFocusedComponent, focusGained, focusLost, + keyPressed, keyStateChanged */ - static Component* JUCE_CALLTYPE getCurrentlyModalComponent (int index = 0) throw(); + void grabKeyboardFocus(); - /** Checks whether there's a modal component somewhere that's stopping this one - from receiving messages. + /** Returns true if this component currently has the keyboard focus. - If there is a modal component, its canModalEventBeSentToComponent() method - will be called to see if it will still allow this component to receive events. + @param trueIfChildIsFocused if this is true, then the method returns true if + either this component or any of its children (recursively) + have the focus. If false, the method only returns true if + this component has the focus. - @see runModalLoop, getCurrentlyModalComponent + @see grabKeyboardFocus, setWantsKeyboardFocus, getCurrentlyFocusedComponent, + focusGained, focusLost */ - bool isCurrentlyBlockedByAnotherModalComponent() const throw(); - - /** When a component is modal, this callback allows it to choose which other - components can still receive events. + bool hasKeyboardFocus (const bool trueIfChildIsFocused) const throw(); - When a modal component is active and the user clicks on a non-modal component, - this method is called on the modal component, and if it returns true, the - event is allowed to reach its target. If it returns false, the event is blocked - and the inputAttemptWhenModal() callback is made. + /** Returns the component that currently has the keyboard focus. - It called by the isCurrentlyBlockedByAnotherModalComponent() method. The default - implementation just returns false in all cases. + @returns the focused component, or null if nothing is focused. */ - virtual bool canModalEventBeSentToComponent (const Component* targetComponent); + static Component* JUCE_CALLTYPE getCurrentlyFocusedComponent() throw(); - /** Called when the user tries to click on a component that is blocked by another - modal component. + /** Tries to move the keyboard focus to one of this component's siblings. - When a component is modal and the user clicks on one of the other components, - the modal component will receive this callback. + This will try to move focus to either the next or previous component. (This + is the method that is used when shifting focus by pressing the tab key). - The default implementation of this method will play a beep, and bring the currently - modal component to the front, but it can be overridden to do other tasks. + Components for which getWantsKeyboardFocus() returns false are not looked at. - @see isCurrentlyBlockedByAnotherModalComponent, canModalEventBeSentToComponent + @param moveToNext if true, the focus will move forwards; if false, it will + move backwards + @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus */ - virtual void inputAttemptWhenModal(); + void moveKeyboardFocusToSibling (const bool moveToNext); - /** Returns one of the component's properties as a string. + /** Creates a KeyboardFocusTraverser object to use to determine the logic by + which focus should be passed from this component. - @param keyName the name of the property to retrieve - @param useParentComponentIfNotFound if this is true and the key isn't present in this component's - properties, then it will check whether the parent component has - the key. - @param defaultReturnValue a value to return if the named property doesn't actually exist - */ - const String getComponentProperty (const String& keyName, - const bool useParentComponentIfNotFound, - const String& defaultReturnValue = String::empty) const throw(); + The default implementation of this method will return a default + KeyboardFocusTraverser if this component is a focus container (as determined + by the setFocusContainer() method). If the component isn't a focus + container, then it will recursively ask its parents for a KeyboardFocusTraverser. - /** Returns one of the properties as an integer. + If you overrride this to return a custom KeyboardFocusTraverser, then + this component and all its sub-components will use the new object to + make their focusing decisions. - @param keyName the name of the property to retrieve - @param useParentComponentIfNotFound if this is true and the key isn't present in this component's - properties, then it will check whether the parent component has - the key. - @param defaultReturnValue a value to return if the named property doesn't actually exist + The method should return a new object, which the caller is required to + delete when no longer needed. */ - int getComponentPropertyInt (const String& keyName, - const bool useParentComponentIfNotFound, - const int defaultReturnValue = 0) const throw(); + virtual KeyboardFocusTraverser* createFocusTraverser(); - /** Returns one of the properties as an double. + /** Returns the focus order of this component, if one has been specified. - @param keyName the name of the property to retrieve - @param useParentComponentIfNotFound if this is true and the key isn't present in this component's - properties, then it will check whether the parent component has - the key. - @param defaultReturnValue a value to return if the named property doesn't actually exist - */ - double getComponentPropertyDouble (const String& keyName, - const bool useParentComponentIfNotFound, - const double defaultReturnValue = 0.0) const throw(); + By default components don't have a focus order - in that case, this + will return 0. Lower numbers indicate that the component will be + earlier in the focus traversal order. - /** Returns one of the properties as an boolean. + To change the order, call setExplicitFocusOrder(). - The result will be true if the string found for this key name can be parsed as a non-zero - integer. + The focus order may be used by the KeyboardFocusTraverser class as part of + its algorithm for deciding the order in which components should be traversed. + See the KeyboardFocusTraverser class for more details on this. - @param keyName the name of the property to retrieve - @param useParentComponentIfNotFound if this is true and the key isn't present in this component's - properties, then it will check whether the parent component has - the key. - @param defaultReturnValue a value to return if the named property doesn't actually exist + @see moveKeyboardFocusToSibling, createFocusTraverser, KeyboardFocusTraverser */ - bool getComponentPropertyBool (const String& keyName, - const bool useParentComponentIfNotFound, - const bool defaultReturnValue = false) const throw(); - - /** Returns one of the properties as an colour. + int getExplicitFocusOrder() const throw(); - @param keyName the name of the property to retrieve - @param useParentComponentIfNotFound if this is true and the key isn't present in this component's - properties, then it will check whether the parent component has - the key. - @param defaultReturnValue a colour to return if the named property doesn't actually exist - */ - const Colour getComponentPropertyColour (const String& keyName, - const bool useParentComponentIfNotFound, - const Colour& defaultReturnValue = Colours::black) const throw(); + /** Sets the index used in determining the order in which focusable components + should be traversed. - /** Sets a named property as a string. + A value of 0 or less is taken to mean that no explicit order is wanted, and + that traversal should use other factors, like the component's position. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - @see removeComponentProperty + @see getExplicitFocusOrder, moveKeyboardFocusToSibling */ - void setComponentProperty (const String& keyName, const String& value) throw(); + void setExplicitFocusOrder (const int newFocusOrderIndex) throw(); - /** Sets a named property to an integer. + /** Indicates whether this component is a parent for components that can have + their focus traversed. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - @see removeComponentProperty - */ - void setComponentProperty (const String& keyName, const int value) throw(); + This flag is used by the default implementation of the createFocusTraverser() + method, which uses the flag to find the first parent component (of the currently + focused one) which wants to be a focus container. - /** Sets a named property to a double. + So using this method to set the flag to 'true' causes this component to + act as the top level within which focus is passed around. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - @see removeComponentProperty + @see isFocusContainer, createFocusTraverser, moveKeyboardFocusToSibling */ - void setComponentProperty (const String& keyName, const double value) throw(); - - /** Sets a named property to a boolean. + void setFocusContainer (const bool shouldBeFocusContainer) throw(); - @param keyName the name of the property to set. (This mustn't be an empty string) - @param value the new value to set it to - @see removeComponentProperty - */ - void setComponentProperty (const String& keyName, const bool value) throw(); + /** Returns true if this component has been marked as a focus container. - /** Sets a named property to a colour. + See setFocusContainer() for more details. - @param keyName the name of the property to set. (This mustn't be an empty string) - @param newColour the new colour to set it to - @see removeComponentProperty + @see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser */ - void setComponentProperty (const String& keyName, const Colour& newColour) throw(); - - /** Deletes a named component property. + bool isFocusContainer() const throw(); - @param keyName the name of the property to delete. (This mustn't be an empty string) - @see setComponentProperty, getComponentProperty - */ - void removeComponentProperty (const String& keyName) throw(); + /** Returns true if the component (and all its parents) are enabled. - /** Returns the complete set of properties that have been set for this component. + Components are enabled by default, and can be disabled with setEnabled(). Exactly + what difference this makes to the component depends on the type. E.g. buttons + and sliders will choose to draw themselves differently, etc. - If no properties have been set, this will return a null pointer. + Note that if one of this component's parents is disabled, this will always + return false, even if this component itself is enabled. - @see getComponentProperty, setComponentProperty + @see setEnabled, enablementChanged */ - PropertySet* getComponentProperties() const throw() { return propertySet_; } + bool isEnabled() const throw(); - /** Looks for a colour that has been registered with the given colour ID number. + /** Enables or disables this component. - If a colour has been set for this ID number using setColour(), then it is - returned. If none has been set, the method will try calling the component's - LookAndFeel class's findColour() method. If none has been registered with the - look-and-feel either, it will just return black. + Disabling a component will also cause all of its child components to become + disabled. - The colour IDs for various purposes are stored as enums in the components that - they are relevent to - for an example, see Slider::ColourIds, - Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. + Similarly, enabling a component which is inside a disabled parent + component won't make any difference until the parent is re-enabled. - @see setColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour + @see isEnabled, enablementChanged */ - const Colour findColour (const int colourId, const bool inheritFromParent = false) const throw(); + void setEnabled (const bool shouldBeEnabled); - /** Registers a colour to be used for a particular purpose. + /** Callback to indicate that this component has been enabled or disabled. - Changing a colour will cause a synchronous callback to the colourChanged() - method, which your component can override if it needs to do something when - colours are altered. + This can be triggered by one of the component's parent components + being enabled or disabled, as well as changes to the component itself. - For more details about colour IDs, see the comments for findColour(). + The default implementation of this method does nothing; your class may + wish to repaint itself or something when this happens. - @see findColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour + @see setEnabled, isEnabled */ - void setColour (const int colourId, const Colour& colour); + virtual void enablementChanged(); - /** If a colour has been set with setColour(), this will remove it. + /** Changes the mouse cursor shape to use when the mouse is over this component. - This allows you to make a colour revert to its default state. - */ - void removeColour (const int colourId); + Note that the cursor set by this method can be overridden by the getMouseCursor + method. - /** Returns true if the specified colour ID has been explicitly set for this - component using the setColour() method. + @see MouseCursor */ - bool isColourSpecified (const int colourId) const throw(); + void setMouseCursor (const MouseCursor& cursorType) throw(); - /** This looks for any colours that have been specified for this component, - and copies them to the specified target component. - */ - void copyAllExplicitColoursTo (Component& target) const throw(); + /** Returns the mouse cursor shape to use when the mouse is over this component. - /** This method is called when a colour is changed by the setColour() method. + The default implementation will return the cursor that was set by setCursor() + but can be overridden for more specialised purposes, e.g. returning different + cursors depending on the mouse position. - @see setColour, findColour + @see MouseCursor */ - virtual void colourChanged(); - - /** Returns the underlying native window handle for this component. + virtual const MouseCursor getMouseCursor(); - This is platform-dependent and strictly for power-users only! - */ - void* getWindowHandle() const throw(); + /** Forces the current mouse cursor to be updated. - /** When created, each component is given a number to uniquely identify it. + If you're overriding the getMouseCursor() method to control which cursor is + displayed, then this will only be checked each time the user moves the mouse. So + if you want to force the system to check that the cursor being displayed is + up-to-date (even if the mouse is just sitting there), call this method. - The number is incremented each time a new component is created, so it's a more - unique way of identifying a component than using its memory location (which - may be reused after the component is deleted, of course). + This isn't needed if you're only using setMouseCursor(). */ - uint32 getComponentUID() const throw() { return componentUID; } + void updateMouseCursor() const throw(); - juce_UseDebuggingNewOperator + /** Components can override this method to draw their content. -private: + The paint() method gets called when a region of a component needs redrawing, + either because the component's repaint() method has been called, or because + something has happened on the screen that means a section of a window needs + to be redrawn. - friend class ComponentPeer; - friend class InternalDragRepeater; + Any child components will draw themselves over whatever this method draws. If + you need to paint over the top of your child components, you can also implement + the paintOverChildren() method to do this. - static Component* currentlyFocusedComponent; - static Component* componentUnderMouse; + If you want to cause a component to redraw itself, this is done asynchronously - + calling the repaint() method marks a region of the component as "dirty", and the + paint() method will automatically be called sometime later, by the message thread, + to paint any bits that need refreshing. In Juce (and almost all modern UI frameworks), + you never redraw something synchronously. - String componentName_; - Component* parentComponent_; - uint32 componentUID; - Rectangle bounds_; - unsigned short numDeepMouseListeners; - Array childComponentList_; - LookAndFeel* lookAndFeel_; - MouseCursor cursor_; - ImageEffectFilter* effect_; - Image* bufferedImage_; - VoidArray* mouseListeners_; - VoidArray* keyListeners_; - VoidArray* componentListeners_; - PropertySet* propertySet_; + You should never need to call this method directly - to take a snapshot of the + component you could use createComponentSnapshot() or paintEntireComponent(). - struct ComponentFlags - { - bool hasHeavyweightPeerFlag : 1; - bool visibleFlag : 1; - bool opaqueFlag : 1; - bool ignoresMouseClicksFlag : 1; - bool allowChildMouseClicksFlag : 1; - bool wantsFocusFlag : 1; - bool isFocusContainerFlag : 1; - bool dontFocusOnMouseClickFlag : 1; - bool alwaysOnTopFlag : 1; - bool bufferToImageFlag : 1; - bool bringToFrontOnClickFlag : 1; - bool repaintOnMouseActivityFlag : 1; - bool draggingFlag : 1; - bool mouseOverFlag : 1; - bool mouseInsideFlag : 1; - bool currentlyModalFlag : 1; - bool isDisabledFlag : 1; - bool childCompFocusedFlag : 1; -#ifdef JUCE_DEBUG - bool isInsidePaintCall : 1; -#endif - }; + @param g the graphics context that must be used to do the drawing operations. + @see repaint, paintOverChildren, Graphics + */ + virtual void paint (Graphics& g); - union - { - uint32 componentFlags_; - ComponentFlags flags; - }; + /** Components can override this method to draw over the top of their children. - void internalMouseEnter (int x, int y, const int64 time); - void internalMouseExit (int x, int y, const int64 time); - void internalMouseDown (int x, int y); - void internalMouseUp (const int oldModifiers, int x, int y, const int64 time); - void internalMouseDrag (int x, int y, const int64 time); - void internalMouseMove (int x, int y, const int64 time); - void internalMouseWheel (const int intAmountX, const int intAmountY, const int64 time); - void internalBroughtToFront(); - void internalFocusGain (const FocusChangeType cause); - void internalFocusLoss (const FocusChangeType cause); - void internalChildFocusChange (FocusChangeType cause); - void internalModalInputAttempt(); - void internalModifierKeysChanged(); - void internalChildrenChanged(); - void internalHierarchyChanged(); - void internalUpdateMouseCursor (const bool forcedUpdate) throw(); - void sendMovedResizedMessages (const bool wasMoved, const bool wasResized); - void repaintParent() throw(); - void sendFakeMouseMove() const; - void takeKeyboardFocus (const FocusChangeType cause); - void grabFocusInternal (const FocusChangeType cause, const bool canTryParent = true); - static void giveAwayFocus(); - void sendEnablementChangeMessage(); - static void* runModalLoopCallback (void*); - static void bringModalComponentToFront(); - void subtractObscuredRegions (RectangleList& result, - const int deltaX, const int deltaY, - const Rectangle& clipRect, - const Component* const compToAvoid) const throw(); - void clipObscuredRegions (Graphics& g, const Rectangle& clipRect, - const int deltaX, const int deltaY) const throw(); + For most drawing operations, it's better to use the normal paint() method, + but if you need to overlay something on top of the children, this can be + used. - // how much of the component is not off the edges of its parents - const Rectangle getUnclippedArea() const; - void sendVisibilityChangeMessage(); + @see paint, Graphics + */ + virtual void paintOverChildren (Graphics& g); - // This is included here just to cause a compile error if your code is still handling - // drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget - // class, which is easy (just make your class inherit from FileDragAndDropTarget, and - // implement its methods instead of this Component method). - virtual void filesDropped (const StringArray&, int, int) {} + /** Called when the mouse moves inside this component. - // components aren't allowed to have copy constructors, as this would mess up parent - // hierarchies. You might need to give your subclasses a private dummy constructor like - // this one to avoid compiler warnings. - Component (const Component&); + If the mouse button isn't pressed and the mouse moves over a component, + this will be called to let the component react to this. - const Component& operator= (const Component&); + A component will always get a mouseEnter callback before a mouseMove. - // (dummy method to cause a deliberate compile error - if you hit this, you need to update your - // subclass to use the new parameters to keyStateChanged) - virtual void keyStateChanged() {}; + @param e details about the position and status of the mouse event + @see mouseEnter, mouseExit, mouseDrag, contains + */ + virtual void mouseMove (const MouseEvent& e); -protected: - /** @internal */ - virtual void internalRepaint (int x, int y, int w, int h); + /** Called when the mouse first enters this component. - virtual ComponentPeer* createNewPeer (int styleFlags, void* nativeWindowToAttachTo); + If the mouse button isn't pressed and the mouse moves into a component, + this will be called to let the component react to this. - /** Overridden from the MessageListener parent class. + When the mouse button is pressed and held down while being moved in + or out of a component, no mouseEnter or mouseExit callbacks are made - only + mouseDrag messages are sent to the component that the mouse was originally + clicked on, until the button is released. - You can override this if you really need to, but be sure to pass your unwanted messages up - to this base class implementation, as the Component class needs to send itself messages - to work properly. + If you're writing a component that needs to repaint itself when the mouse + enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() + method. + + @param e details about the position and status of the mouse event + @see mouseExit, mouseDrag, mouseMove, contains */ - void handleMessage (const Message&); -}; + virtual void mouseEnter (const MouseEvent& e); -#endif // __JUCE_COMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_Component.h *********/ + /** Called when the mouse moves out of this component. -/********* Start of inlined file: juce_ApplicationCommandInfo.h *********/ -#ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ -#define __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ + This will be called when the mouse moves off the edge of this + component. -/********* Start of inlined file: juce_ApplicationCommandID.h *********/ -#ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ -#define __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ + If the mouse button was pressed, and it was then dragged off the + edge of the component and released, then this callback will happen + when the button is released, after the mouseUp callback. -/** A type used to hold the unique ID for an application command. + If you're writing a component that needs to repaint itself when the mouse + enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() + method. - This is a numeric type, so it can be stored as an integer. + @param e details about the position and status of the mouse event + @see mouseEnter, mouseDrag, mouseMove, contains + */ + virtual void mouseExit (const MouseEvent& e); - @see ApplicationCommandInfo, ApplicationCommandManager, - ApplicationCommandTarget, KeyPressMappingSet -*/ -typedef int CommandID; + /** Called when a mouse button is pressed while it's over this component. -/** A set of general-purpose application command IDs. + The MouseEvent object passed in contains lots of methods for finding out + which button was pressed, as well as which modifier keys (e.g. shift, ctrl) + were held down at the time. - Because these commands are likely to be used in most apps, they're defined - here to help different apps to use the same numeric values for them. + Once a button is held down, the mouseDrag method will be called when the + mouse moves, until the button is released. - Of course you don't have to use these, but some of them are used internally by - Juce - e.g. the quit ID is recognised as a command by the JUCEApplication class. + @param e details about the position and status of the mouse event + @see mouseUp, mouseDrag, mouseDoubleClick, contains + */ + virtual void mouseDown (const MouseEvent& e); - @see ApplicationCommandInfo, ApplicationCommandManager, - ApplicationCommandTarget, KeyPressMappingSet -*/ -namespace StandardApplicationCommandIDs -{ - /** This command ID should be used to send a "Quit the App" command. + /** Called when the mouse is moved while a button is held down. - This command is recognised by the JUCEApplication class, so if it is invoked - and no other ApplicationCommandTarget handles the event first, the JUCEApplication - object will catch it and call JUCEApplication::systemRequestedQuit(). - */ - static const CommandID quit = 0x1001; + When a mouse button is pressed inside a component, that component + receives mouseDrag callbacks each time the mouse moves, even if the + mouse strays outside the component's bounds. - /** The command ID that should be used to send a "Delete" command. */ - static const CommandID del = 0x1002; + If you want to be able to drag things off the edge of a component + and have the component scroll when you get to the edges, the + beginDragAutoRepeat() method might be useful. - /** The command ID that should be used to send a "Cut" command. */ - static const CommandID cut = 0x1003; + @param e details about the position and status of the mouse event + @see mouseDown, mouseUp, mouseMove, contains, beginDragAutoRepeat + */ + virtual void mouseDrag (const MouseEvent& e); - /** The command ID that should be used to send a "Copy to clipboard" command. */ - static const CommandID copy = 0x1004; + /** Called when a mouse button is released. - /** The command ID that should be used to send a "Paste from clipboard" command. */ - static const CommandID paste = 0x1005; + A mouseUp callback is sent to the component in which a button was pressed + even if the mouse is actually over a different component when the + button is released. - /** The command ID that should be used to send a "Select all" command. */ - static const CommandID selectAll = 0x1006; + The MouseEvent object passed in contains lots of methods for finding out + which buttons were down just before they were released. - /** The command ID that should be used to send a "Deselect all" command. */ - static const CommandID deselectAll = 0x1007; -} + @param e details about the position and status of the mouse event + @see mouseDown, mouseDrag, mouseDoubleClick, contains + */ + virtual void mouseUp (const MouseEvent& e); -#endif // __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ -/********* End of inlined file: juce_ApplicationCommandID.h *********/ + /** Called when a mouse button has been double-clicked in this component. -/** - Holds information describing an application command. + The MouseEvent object passed in contains lots of methods for finding out + which button was pressed, as well as which modifier keys (e.g. shift, ctrl) + were held down at the time. - This object is used to pass information about a particular command, such as its - name, description and other usage flags. + For altering the time limit used to detect double-clicks, + see MouseEvent::setDoubleClickTimeout. - When an ApplicationCommandTarget is asked to provide information about the commands - it can perform, this is the structure gets filled-in to describe each one. + @param e details about the position and status of the mouse event + @see mouseDown, mouseUp, MouseEvent::setDoubleClickTimeout, + MouseEvent::getDoubleClickTimeout + */ + virtual void mouseDoubleClick (const MouseEvent& e); - @see ApplicationCommandTarget, ApplicationCommandTarget::getCommandInfo(), - ApplicationCommandManager -*/ -struct JUCE_API ApplicationCommandInfo -{ + /** Called when the mouse-wheel is moved. - ApplicationCommandInfo (const CommandID commandID) throw(); + This callback is sent to the component that the mouse is over when the + wheel is moved. - /** Sets a number of the structures values at once. + If not overridden, the component will forward this message to its parent, so + that parent components can collect mouse-wheel messages that happen to + child components which aren't interested in them. - The meanings of each of the parameters is described below, in the appropriate - member variable's description. + @param e details about the position and status of the mouse event + @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive + value means the wheel has been pushed to the right, negative means it + was pushed to the left + @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive + value means the wheel has been pushed upwards, negative means it + was pushed downwards */ - void setInfo (const String& shortName, - const String& description, - const String& categoryName, - const int flags) throw(); + virtual void mouseWheelMove (const MouseEvent& e, + float wheelIncrementX, + float wheelIncrementY); - /** An easy way to set or remove the isDisabled bit in the structure's flags field. + /** Ensures that a non-stop stream of mouse-drag events will be sent during the + next mouse-drag operation. - If isActive is true, the flags member has the isDisabled bit cleared; if isActive - is false, the bit is set. - */ - void setActive (const bool isActive) throw(); + This allows you to make sure that mouseDrag() events sent continuously, even + when the mouse isn't moving. This can be useful for things like auto-scrolling + components when the mouse is near an edge. - /** An easy way to set or remove the isTicked bit in the structure's flags field. - */ - void setTicked (const bool isTicked) throw(); + Call this method during a mouseDown() or mouseDrag() callback, specifying the + minimum interval between consecutive mouse drag callbacks. The callbacks + will continue until the mouse is released, and then the interval will be reset, + so you need to make sure it's called every time you begin a drag event. If it + is called when the mouse isn't actually being pressed, it will apply to the next + mouse-drag operation that happens. - /** Handy method for adding a keypress to the defaultKeypresses array. + Passing an interval of 0 or less will cancel the auto-repeat. - This is just so you can write things like: - @code - myinfo.addDefaultKeypress (T('s'), ModifierKeys::commandModifier); - @endcode - instead of - @code - myinfo.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::commandModifier)); - @endcode + @see mouseDrag */ - void addDefaultKeypress (const int keyCode, - const ModifierKeys& modifiers) throw(); + static void beginDragAutoRepeat (const int millisecondIntervalBetweenCallbacks); - /** The command's unique ID number. - */ - CommandID commandID; + /** Causes automatic repaints when the mouse enters or exits this component. - /** A short name to describe the command. + If turned on, then when the mouse enters/exits, or when the button is pressed/released + on the component, it will trigger a repaint. - This should be suitable for use in menus, on buttons that trigger the command, etc. + This is handy for things like buttons that need to draw themselves differently when + the mouse moves over them, and it avoids having to override all the different mouse + callbacks and call repaint(). - You can use the setInfo() method to quickly set this and some of the command's - other properties. + @see mouseEnter, mouseExit, mouseDown, mouseUp */ - String shortName; + void setRepaintsOnMouseActivity (const bool shouldRepaint) throw(); - /** A longer description of the command. + /** Registers a listener to be told when mouse events occur in this component. - This should be suitable for use in contexts such as a KeyMappingEditorComponent or - pop-up tooltip describing what the command does. + If you need to get informed about mouse events in a component but can't or + don't want to override its methods, you can attach any number of listeners + to the component, and these will get told about the events in addition to + the component's own callbacks being called. - You can use the setInfo() method to quickly set this and some of the command's - other properties. - */ - String description; + Note that a MouseListener can also be attached to more than one component. - /** A named category that the command fits into. + @param newListener the listener to register + @param wantsEventsForAllNestedChildComponents if true, the listener will receive callbacks + for events that happen to any child component + within this component, including deeply-nested + child components. If false, it will only be + told about events that this component handles. + @see MouseListener, removeMouseListener + */ + void addMouseListener (MouseListener* const newListener, + const bool wantsEventsForAllNestedChildComponents) throw(); - You can give your commands any category you like, and these will be displayed in - contexts such as the KeyMappingEditorComponent, where the category is used to group - commands together. + /** Deregisters a mouse listener. - You can use the setInfo() method to quickly set this and some of the command's - other properties. + @see addMouseListener, MouseListener */ - String categoryName; + void removeMouseListener (MouseListener* const listenerToRemove) throw(); - /** A list of zero or more keypresses that should be used as the default keys for - this command. + /** Adds a listener that wants to hear about keypresses that this component receives. - Methods such as KeyPressMappingSet::resetToDefaultMappings() will use the keypresses in - this list to initialise the default set of key-to-command mappings. + The listeners that are registered with a component are called by its keyPressed() or + keyStateChanged() methods (assuming these haven't been overridden to do something else). - @see addDefaultKeypress + If you add an object as a key listener, be careful to remove it when the object + is deleted, or the component will be left with a dangling pointer. + + @see keyPressed, keyStateChanged, removeKeyListener */ - Array defaultKeypresses; + void addKeyListener (KeyListener* const newListener) throw(); - /** Flags describing the ways in which this command should be used. + /** Removes a previously-registered key listener. - A bitwise-OR of these values is stored in the ApplicationCommandInfo::flags - variable. + @see addKeyListener */ - enum CommandFlags - { - /** Indicates that the command can't currently be performed. + void removeKeyListener (KeyListener* const listenerToRemove) throw(); - The ApplicationCommandTarget::getCommandInfo() method must set this flag if it's - not currently permissable to perform the command. If the flag is set, then - components that trigger the command, e.g. PopupMenu, may choose to grey-out the - command or show themselves as not being enabled. + /** Called when a key is pressed. - @see ApplicationCommandInfo::setActive - */ - isDisabled = 1 << 0, + When a key is pressed, the component that has the keyboard focus will have this + method called. Remember that a component will only be given the focus if its + setWantsKeyboardFocus() method has been used to enable this. - /** Indicates that the command should have a tick next to it on a menu. + If your implementation returns true, the event will be consumed and not passed + on to any other listeners. If it returns false, the key will be passed to any + KeyListeners that have been registered with this component. As soon as one of these + returns true, the process will stop, but if they all return false, the event will + be passed upwards to this component's parent, and so on. - If your command is shown on a menu and this is set, it'll show a tick next to - it. Other components such as buttons may also use this flag to indicate that it - is a value that can be toggled, and is currently in the 'on' state. + The default implementation of this method does nothing and returns false. - @see ApplicationCommandInfo::setTicked - */ - isTicked = 1 << 1, + @see keyStateChanged, getCurrentlyFocusedComponent, addKeyListener + */ + virtual bool keyPressed (const KeyPress& key); - /** If this flag is present, then when a KeyPressMappingSet invokes the command, - it will call the command twice, once on key-down and again on key-up. + /** Called when a key is pressed or released. - @see ApplicationCommandTarget::InvocationInfo - */ - wantsKeyUpDownCallbacks = 1 << 2, + Whenever a key on the keyboard is pressed or released (including modifier keys + like shift and ctrl), this method will be called on the component that currently + has the keyboard focus. Remember that a component will only be given the focus if + its setWantsKeyboardFocus() method has been used to enable this. - /** If this flag is present, then a KeyMappingEditorComponent will not display the - command in its list. - */ - hiddenFromKeyEditor = 1 << 3, + If your implementation returns true, the event will be consumed and not passed + on to any other listeners. If it returns false, then any KeyListeners that have + been registered with this component will have their keyStateChanged methods called. + As soon as one of these returns true, the process will stop, but if they all return + false, the event will be passed upwards to this component's parent, and so on. - /** If this flag is present, then a KeyMappingEditorComponent will display the - command in its list, but won't allow the assigned keypress to be changed. - */ - readOnlyInKeyEditor = 1 << 4, + The default implementation of this method does nothing and returns false. - /** If this flag is present and the command is invoked from a keypress, then any - buttons or menus that are also connected to the command will not flash to - indicate that they've been triggered. - */ - dontTriggerVisualFeedback = 1 << 5 - }; + To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() + method. - /** A bitwise-OR of the values specified in the CommandFlags enum. + @param isKeyDown true if a key has been pressed; false if it has been released - You can use the setInfo() method to quickly set this and some of the command's - other properties. + @see keyPressed, KeyPress, getCurrentlyFocusedComponent, addKeyListener */ - int flags; -}; + virtual bool keyStateChanged (const bool isKeyDown); -#endif // __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ -/********* End of inlined file: juce_ApplicationCommandInfo.h *********/ + /** Called when a modifier key is pressed or released. -/** - A command target publishes a list of command IDs that it can perform. + Whenever the shift, control, alt or command keys are pressed or released, + this method will be called on the component that currently has the keyboard focus. + Remember that a component will only be given the focus if its setWantsKeyboardFocus() + method has been used to enable this. - An ApplicationCommandManager despatches commands to targets, which must be - able to provide information about what commands they can handle. + The default implementation of this method actually calls its parent's modifierKeysChanged + method, so that focused components which aren't interested in this will give their + parents a chance to act on the event instead. - To create a target, you'll need to inherit from this class, implementing all of - its pure virtual methods. + @see keyStateChanged, ModifierKeys + */ + virtual void modifierKeysChanged (const ModifierKeys& modifiers); - For info about how a target is chosen to receive a command, see - ApplicationCommandManager::getFirstCommandTarget(). + /** Enumeration used by the focusChanged() and focusLost() methods. */ + enum FocusChangeType + { + focusChangedByMouseClick, /**< Means that the user clicked the mouse to change focus. */ + focusChangedByTabKey, /**< Means that the user pressed the tab key to move the focus. */ + focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */ + }; - @see ApplicationCommandManager, ApplicationCommandInfo -*/ -class JUCE_API ApplicationCommandTarget -{ -public: + /** Called to indicate that this component has just acquired the keyboard focus. - /** Creates a command target. */ - ApplicationCommandTarget(); + @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + */ + virtual void focusGained (FocusChangeType cause); - /** Destructor. */ - virtual ~ApplicationCommandTarget(); + /** Called to indicate that this component has just lost the keyboard focus. - /** + @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ - struct JUCE_API InvocationInfo - { - - InvocationInfo (const CommandID commandID) throw(); + virtual void focusLost (FocusChangeType cause); - /** The UID of the command that should be performed. */ - CommandID commandID; + /** Called to indicate that one of this component's children has been focused or unfocused. - /** The command's flags. + Essentially this means that the return value of a call to hasKeyboardFocus (true) has + changed. It happens when focus moves from one of this component's children (at any depth) + to a component that isn't contained in this one, (or vice-versa). - See ApplicationCommandInfo for a description of these flag values. - */ - int commandFlags; + @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus + */ + virtual void focusOfChildComponentChanged (FocusChangeType cause); - /** The types of context in which the command might be called. */ - enum InvocationMethod - { - direct = 0, /**< The command is being invoked directly by a piece of code. */ - fromKeyPress, /**< The command is being invoked by a key-press. */ - fromMenu, /**< The command is being invoked by a menu selection. */ - fromButton /**< The command is being invoked by a button click. */ - }; + /** Returns true if the mouse is currently over this component. - /** The type of event that triggered this command. */ - InvocationMethod invocationMethod; + If the mouse isn't over the component, this will return false, even if the + mouse is currently being dragged - so you can use this in your mouseDrag + method to find out whether it's really over the component or not. - /** If triggered by a keypress or menu, this will be the component that had the - keyboard focus at the time. + Note that when the mouse button is being held down, then the only component + for which this method will return true is the one that was originally + clicked on. - If triggered by a button, it may be set to that component, or it may be null. - */ - Component* originatingComponent; + @see isMouseButtonDown. isMouseOverOrDragging, mouseDrag + */ + bool isMouseOver() const throw(); - /** The keypress that was used to invoke it. + /** Returns true if the mouse button is currently held down in this component. - Note that this will be an invalid keypress if the command was invoked - by some other means than a keyboard shortcut. - */ - KeyPress keyPress; + Note that this is a test to see whether the mouse is being pressed in this + component, so it'll return false if called on component A when the mouse + is actually being dragged in component B. - /** True if the callback is being invoked when the key is pressed, - false if the key is being released. + @see isMouseButtonDownAnywhere, isMouseOver, isMouseOverOrDragging + */ + bool isMouseButtonDown() const throw(); - @see KeyPressMappingSet::addCommand() - */ - bool isKeyDown; + /** True if the mouse is over this component, or if it's being dragged in this component. - /** If the key is being released, this indicates how long it had been held - down for. + This is a handy equivalent to (isMouseOver() || isMouseButtonDown()). - (Only relevant if isKeyDown is false.) - */ - int millisecsSinceKeyPressed; - }; + @see isMouseOver, isMouseButtonDown, isMouseButtonDownAnywhere + */ + bool isMouseOverOrDragging() const throw(); - /** This must return the next target to try after this one. + /** Returns true if a mouse button is currently down. - When a command is being sent, and the first target can't handle - that command, this method is used to determine the next target that should - be tried. + Unlike isMouseButtonDown, this will test the current state of the + buttons without regard to which component (if any) it has been + pressed in. - It may return 0 if it doesn't know of another target. + @see isMouseButtonDown, ModifierKeys + */ + static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw(); - If your target is a Component, you would usually use the findFirstTargetParentComponent() - method to return a parent component that might want to handle it. + /** Returns the mouse's current position, relative to this component. - @see invoke + The co-ordinates are relative to the component's top-left corner. */ - virtual ApplicationCommandTarget* getNextCommandTarget() = 0; + void getMouseXYRelative (int& x, int& y) const throw(); - /** This must return a complete list of commands that this target can handle. + /** Returns the component that's currently underneath the mouse. - Your target should add all the command IDs that it handles to the array that is - passed-in. + @returns the component or 0 if there isn't one. + @see contains, getComponentAt */ - virtual void getAllCommands (Array & commands) = 0; + static Component* JUCE_CALLTYPE getComponentUnderMouse() throw(); - /** This must provide details about one of the commands that this target can perform. + /** Allows the mouse to move beyond the edges of the screen. - This will be called with one of the command IDs that the target provided in its - getAllCommands() methods. + Calling this method when the mouse button is currently pressed inside this component + will remove the cursor from the screen and allow the mouse to (seem to) move beyond + the edges of the screen. - It should fill-in all appropriate fields of the ApplicationCommandInfo structure with - suitable information about the command. (The commandID field will already have been filled-in - by the caller). + This means that the co-ordinates returned to mouseDrag() will be unbounded, and this + can be used for things like custom slider controls or dragging objects around, where + movement would be otherwise be limited by the mouse hitting the edges of the screen. - The easiest way to set the info is using the ApplicationCommandInfo::setInfo() method to - set all the fields at once. + The unbounded mode is automatically turned off when the mouse button is released, or + it can be turned off explicitly by calling this method again. - If the command is currently inactive for some reason, this method must use - ApplicationCommandInfo::setActive() to make that clear, (or it should set the isDisabled - bit of the ApplicationCommandInfo::flags field). + @param shouldUnboundedMovementBeEnabled whether to turn this mode on or off + @param keepCursorVisibleUntilOffscreen if set to false, the cursor will immediately be + hidden; if true, it will only be hidden when it + is moved beyond the edge of the screen + */ + void enableUnboundedMouseMovement (bool shouldUnboundedMovementBeEnabled, + bool keepCursorVisibleUntilOffscreen = false) throw(); - Any default key-presses for the command should be appended to the - ApplicationCommandInfo::defaultKeypresses field. + /** Called when this component's size has been changed. - Note that if you change something that affects the status of the commands - that would be returned by this method (e.g. something that makes some commands - active or inactive), you should call ApplicationCommandManager::commandStatusChanged() - to cause the manager to refresh its status. + A component can implement this method to do things such as laying out its + child components when its width or height changes. + + The method is called synchronously as a result of the setBounds or setSize + methods, so repeatedly changing a components size will repeatedly call its + resized method (unlike things like repainting, where multiple calls to repaint + are coalesced together). + + If the component is a top-level window on the desktop, its size could also + be changed by operating-system factors beyond the application's control. + + @see moved, setSize */ - virtual void getCommandInfo (const CommandID commandID, - ApplicationCommandInfo& result) = 0; + virtual void resized(); - /** This must actually perform the specified command. + /** Called when this component's position has been changed. - If this target is able to perform the command specified by the commandID field of the - InvocationInfo structure, then it should do so, and must return true. + This is called when the position relative to its parent changes, not when + its absolute position on the screen changes (so it won't be called for + all child components when a parent component is moved). - If it can't handle this command, it should return false, which tells the caller to pass - the command on to the next target in line. + The method is called synchronously as a result of the setBounds, setTopLeftPosition + or any of the other repositioning methods, and like resized(), it will be + called each time those methods are called. - @see invoke, ApplicationCommandManager::invoke - */ - virtual bool perform (const InvocationInfo& info) = 0; + If the component is a top-level window on the desktop, its position could also + be changed by operating-system factors beyond the application's control. - /** Makes this target invoke a command. + @see resized, setBounds + */ + virtual void moved(); - Your code can call this method to invoke a command on this target, but normally - you'd call it indirectly via ApplicationCommandManager::invoke() or - ApplicationCommandManager::invokeDirectly(). + /** Called when one of this component's children is moved or resized. - If this target can perform the given command, it will call its perform() method to - do so. If not, then getNextCommandTarget() will be used to determine the next target - to try, and the command will be passed along to it. + If the parent wants to know about changes to its immediate children (not + to children of its children), this is the method to override. - @param invocationInfo this must be correctly filled-in, describing the context for - the invocation. - @param asynchronously if false, the command will be performed before this method returns. - If true, a message will be posted so that the command will be performed - later on the message thread, and this method will return immediately. - @see perform, ApplicationCommandManager::invoke + @see moved, resized, parentSizeChanged */ - bool invoke (const InvocationInfo& invocationInfo, - const bool asynchronously); + virtual void childBoundsChanged (Component* child); - /** Invokes a given command directly on this target. + /** Called when this component's immediate parent has been resized. - This is just an easy way to call invoke() without having to fill out the InvocationInfo - structure. + If the component is a top-level window, this indicates that the screen size + has changed. + + @see childBoundsChanged, moved, resized */ - bool invokeDirectly (const CommandID commandID, - const bool asynchronously); + virtual void parentSizeChanged(); - /** Searches this target and all subsequent ones for the first one that can handle - the specified command. + /** Called when this component has been moved to the front of its siblings. - This will use getNextCommandTarget() to determine the chain of targets to try - after this one. + The component may have been brought to the front by the toFront() method, or + by the operating system if it's a top-level window. + + @see toFront */ - ApplicationCommandTarget* getTargetForCommand (const CommandID commandID); + virtual void broughtToFront(); - /** Checks whether this command can currently be performed by this target. + /** Adds a listener to be told about changes to the component hierarchy or position. - This will return true only if a call to getCommandInfo() doesn't set the - isDisabled flag to indicate that the command is inactive. + Component listeners get called when this component's size, position or children + change - see the ComponentListener class for more details. + + @param newListener the listener to register - if this is already registered, it + will be ignored. + @see ComponentListener, removeComponentListener */ - bool isCommandActive (const CommandID commandID); + void addComponentListener (ComponentListener* const newListener) throw(); - /** If this object is a Component, this method will seach upwards in its current - UI hierarchy for the next parent component that implements the - ApplicationCommandTarget class. + /** Removes a component listener. - If your target is a Component, this is a very handy method to use in your - getNextCommandTarget() implementation. + @see addComponentListener */ - ApplicationCommandTarget* findFirstTargetParentComponent(); + void removeComponentListener (ComponentListener* const listenerToRemove) throw(); - juce_UseDebuggingNewOperator + /** Dispatches a numbered message to this component. -private: - // (for async invocation of commands) - class CommandTargetMessageInvoker : public MessageListener - { - public: - CommandTargetMessageInvoker (ApplicationCommandTarget* const owner); - ~CommandTargetMessageInvoker(); + This is a quick and cheap way of allowing simple asynchronous messages to + be sent to components. It's also safe, because if the component that you + send the message to is a null or dangling pointer, this won't cause an error. - void handleMessage (const Message& message); + The command ID is later delivered to the component's handleCommandMessage() method by + the application's message queue. - private: - ApplicationCommandTarget* const owner; + @see handleCommandMessage + */ + void postCommandMessage (const int commandId) throw(); - CommandTargetMessageInvoker (const CommandTargetMessageInvoker&); - const CommandTargetMessageInvoker& operator= (const CommandTargetMessageInvoker&); - }; + /** Called to handle a command that was sent by postCommandMessage(). - CommandTargetMessageInvoker* messageInvoker; + This is called by the message thread when a command message arrives, and + the component can override this method to process it in any way it needs to. - friend class CommandTargetMessageInvoker; - bool tryToInvoke (const InvocationInfo& info, const bool async); + @see postCommandMessage + */ + virtual void handleCommandMessage (int commandId); - ApplicationCommandTarget (const ApplicationCommandTarget&); - const ApplicationCommandTarget& operator= (const ApplicationCommandTarget&); -}; + /** Runs a component modally, waiting until the loop terminates. -#endif // __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ -/********* End of inlined file: juce_ApplicationCommandTarget.h *********/ + This method first makes the component visible, brings it to the front and + gives it the keyboard focus. -/********* Start of inlined file: juce_ActionListener.h *********/ -#ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ -#define __JUCE_ACTIONLISTENER_JUCEHEADER__ + It then runs a loop, dispatching messages from the system message queue, but + blocking all mouse or keyboard messages from reaching any components other + than this one and its children. -/** - Receives callbacks to indicate that some kind of event has occurred. + This loop continues until the component's exitModalState() method is called (or + the component is deleted), and then this method returns, returning the value + passed into exitModalState(). - Used by various classes, e.g. buttons when they are pressed, to tell listeners - about something that's happened. + @see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent, + isCurrentlyBlockedByAnotherModalComponent, MessageManager::dispatchNextMessage + */ + int runModalLoop(); - @see ActionListenerList, ActionBroadcaster, ChangeListener -*/ -class JUCE_API ActionListener -{ -public: - /** Destructor. */ - virtual ~ActionListener() {} + /** Puts the component into a modal state. - /** Overridden by your subclass to receive the callback. + This makes the component modal, so that messages are blocked from reaching + any components other than this one and its children, but unlike runModalLoop(), + this method returns immediately. - @param message the string that was specified when the event was triggered - by a call to ActionListenerList::sendActionMessage() + If takeKeyboardFocus is true, the component will use grabKeyboardFocus() to + get the focus, which is usually what you'll want it to do. If not, it will leave + the focus unchanged. + + @see exitModalState, runModalLoop */ - virtual void actionListenerCallback (const String& message) = 0; -}; + void enterModalState (const bool takeKeyboardFocus = true); -#endif // __JUCE_ACTIONLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_ActionListener.h *********/ + /** Ends a component's modal state. -/** - An instance of this class is used to specify initialisation and shutdown - code for the application. + If this component is currently modal, this will turn of its modalness, and return + a value to the runModalLoop() method that might have be running its modal loop. - An application that wants to run in the JUCE framework needs to declare a - subclass of JUCEApplication and implement its various pure virtual methods. + @see runModalLoop, enterModalState, isCurrentlyModal + */ + void exitModalState (const int returnValue); - It then needs to use the START_JUCE_APPLICATION macro somewhere in a cpp file - to declare an instance of this class and generate a suitable platform-specific - main() function. + /** Returns true if this component is the modal one. - e.g. @code - class MyJUCEApp : public JUCEApplication - { - // NEVER put objects inside a JUCEApplication class - only use pointers to - // objects, which you must create in the initialise() method. - MyApplicationWindow* myMainWindow; + It's possible to have nested modal components, e.g. a pop-up dialog box + that launches another pop-up, but this will only return true for + the one at the top of the stack. - public: - MyJUCEApp() - : myMainWindow (0) - { - // never create any Juce objects in the constructor - do all your initialisation - // in the initialise() method. - } + @see getCurrentlyModalComponent + */ + bool isCurrentlyModal() const throw(); - ~MyJUCEApp() - { - // all your shutdown code must have already been done in the shutdown() method - - // nothing should happen in this destructor. - } + /** Returns the number of components that are currently in a modal state. + @see getCurrentlyModalComponent + */ + static int JUCE_CALLTYPE getNumCurrentlyModalComponents() throw(); - void initialise (const String& commandLine) - { - myMainWindow = new MyApplicationWindow(); - myMainWindow->setBounds (100, 100, 400, 500); - myMainWindow->setVisible (true); - } + /** Returns one of the components that are currently modal. - void shutdown() - { - delete myMainWindow; - } + The index specifies which of the possible modal components to return. The order + of the components in this list is the reverse of the order in which they became + modal - so the component at index 0 is always the active component, and the others + are progressively earlier ones that are themselves now blocked by later ones. - const String getApplicationName() - { - return T("Super JUCE-o-matic"); - } + @returns the modal component, or null if no components are modal (or if the + index is out of range) + @see getNumCurrentlyModalComponents, runModalLoop, isCurrentlyModal + */ + static Component* JUCE_CALLTYPE getCurrentlyModalComponent (int index = 0) throw(); - const String getApplicationVersion() - { - return T("1.0"); - } - }; + /** Checks whether there's a modal component somewhere that's stopping this one + from receiving messages. - // this creates wrapper code to actually launch the app properly. - START_JUCE_APPLICATION (MyJUCEApp) - @endcode + If there is a modal component, its canModalEventBeSentToComponent() method + will be called to see if it will still allow this component to receive events. - Because this object will be created before Juce has properly initialised, you must - NEVER add any member variable objects that will be automatically constructed. Likewise - don't put ANY code in the constructor that could call Juce functions. Any objects that - you want to add to the class must be pointers, which you should instantiate during the - initialise() method, and delete in the shutdown() method. + @see runModalLoop, getCurrentlyModalComponent + */ + bool isCurrentlyBlockedByAnotherModalComponent() const throw(); - @see MessageManager, DeletedAtShutdown -*/ -class JUCE_API JUCEApplication : public ApplicationCommandTarget, - private ActionListener -{ -protected: + /** When a component is modal, this callback allows it to choose which other + components can still receive events. - /** Constructs a JUCE app object. + When a modal component is active and the user clicks on a non-modal component, + this method is called on the modal component, and if it returns true, the + event is allowed to reach its target. If it returns false, the event is blocked + and the inputAttemptWhenModal() callback is made. - If subclasses implement a constructor or destructor, they shouldn't call any - JUCE code in there - put your startup/shutdown code in initialise() and - shutdown() instead. + It called by the isCurrentlyBlockedByAnotherModalComponent() method. The default + implementation just returns false in all cases. */ - JUCEApplication(); + virtual bool canModalEventBeSentToComponent (const Component* targetComponent); -public: - /** Destructor. + /** Called when the user tries to click on a component that is blocked by another + modal component. - If subclasses implement a constructor or destructor, they shouldn't call any - JUCE code in there - put your startup/shutdown code in initialise() and - shutdown() instead. + When a component is modal and the user clicks on one of the other components, + the modal component will receive this callback. + + The default implementation of this method will play a beep, and bring the currently + modal component to the front, but it can be overridden to do other tasks. + + @see isCurrentlyBlockedByAnotherModalComponent, canModalEventBeSentToComponent */ - virtual ~JUCEApplication(); + virtual void inputAttemptWhenModal(); - /** Returns the global instance of the application object being run. */ - static JUCEApplication* getInstance() throw(); + /** Returns one of the component's properties as a string. - /** Called when the application starts. + @param keyName the name of the property to retrieve + @param useParentComponentIfNotFound if this is true and the key isn't present in this component's + properties, then it will check whether the parent component has + the key. + @param defaultReturnValue a value to return if the named property doesn't actually exist + */ + const String getComponentProperty (const String& keyName, + const bool useParentComponentIfNotFound, + const String& defaultReturnValue = String::empty) const throw(); - This will be called once to let the application do whatever initialisation - it needs, create its windows, etc. + /** Returns one of the properties as an integer. - After the method returns, the normal event-dispatch loop will be run, - until the quit() method is called, at which point the shutdown() - method will be called to let the application clear up anything it needs - to delete. + @param keyName the name of the property to retrieve + @param useParentComponentIfNotFound if this is true and the key isn't present in this component's + properties, then it will check whether the parent component has + the key. + @param defaultReturnValue a value to return if the named property doesn't actually exist + */ + int getComponentPropertyInt (const String& keyName, + const bool useParentComponentIfNotFound, + const int defaultReturnValue = 0) const throw(); - If during the initialise() method, the application decides not to start-up - after all, it can just call the quit() method and the event loop won't be run. + /** Returns one of the properties as an double. - @param commandLineParameters the line passed in does not include the - name of the executable, just the parameter list. - @see shutdown, quit + @param keyName the name of the property to retrieve + @param useParentComponentIfNotFound if this is true and the key isn't present in this component's + properties, then it will check whether the parent component has + the key. + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - virtual void initialise (const String& commandLineParameters) = 0; + double getComponentPropertyDouble (const String& keyName, + const bool useParentComponentIfNotFound, + const double defaultReturnValue = 0.0) const throw(); - /** Returns true if the application hasn't yet completed its initialise() method - and entered the main event loop. + /** Returns one of the properties as an boolean. - This is handy for things like splash screens to know when the app's up-and-running - properly. + The result will be true if the string found for this key name can be parsed as a non-zero + integer. + + @param keyName the name of the property to retrieve + @param useParentComponentIfNotFound if this is true and the key isn't present in this component's + properties, then it will check whether the parent component has + the key. + @param defaultReturnValue a value to return if the named property doesn't actually exist */ - bool isInitialising() const throw(); + bool getComponentPropertyBool (const String& keyName, + const bool useParentComponentIfNotFound, + const bool defaultReturnValue = false) const throw(); - /* Called to allow the application to clear up before exiting. + /** Returns one of the properties as an colour. - After JUCEApplication::quit() has been called, the event-dispatch loop will - terminate, and this method will get called to allow the app to sort itself - out. + @param keyName the name of the property to retrieve + @param useParentComponentIfNotFound if this is true and the key isn't present in this component's + properties, then it will check whether the parent component has + the key. + @param defaultReturnValue a colour to return if the named property doesn't actually exist + */ + const Colour getComponentPropertyColour (const String& keyName, + const bool useParentComponentIfNotFound, + const Colour& defaultReturnValue = Colours::black) const throw(); - Be careful that nothing happens in this method that might rely on messages - being sent, or any kind of window activity, because the message loop is no - longer running at this point. + /** Sets a named property as a string. - @see DeletedAtShutdown + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to + @see removeComponentProperty */ - virtual void shutdown() = 0; + void setComponentProperty (const String& keyName, const String& value) throw(); - /** Returns the application's name. + /** Sets a named property to an integer. - An application must implement this to name itself. + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to + @see removeComponentProperty */ - virtual const String getApplicationName() = 0; + void setComponentProperty (const String& keyName, const int value) throw(); - /** Returns the application's version number. + /** Sets a named property to a double. - An application can implement this to give itself a version. - (The default implementation of this just returns an empty string). + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to + @see removeComponentProperty */ - virtual const String getApplicationVersion(); + void setComponentProperty (const String& keyName, const double value) throw(); - /** Checks whether multiple instances of the app are allowed. + /** Sets a named property to a boolean. - If you application class returns true for this, more than one instance is - permitted to run (except on the Mac where this isn't possible). + @param keyName the name of the property to set. (This mustn't be an empty string) + @param value the new value to set it to + @see removeComponentProperty + */ + void setComponentProperty (const String& keyName, const bool value) throw(); - If it's false, the second instance won't start, but it you will still get a - callback to anotherInstanceStarted() to tell you about this - which - gives you a chance to react to what the user was trying to do. + /** Sets a named property to a colour. + + @param keyName the name of the property to set. (This mustn't be an empty string) + @param newColour the new colour to set it to + @see removeComponentProperty */ - virtual bool moreThanOneInstanceAllowed(); + void setComponentProperty (const String& keyName, const Colour& newColour) throw(); - /** Indicates that the user has tried to start up another instance of the app. + /** Deletes a named component property. - This will get called even if moreThanOneInstanceAllowed() is false. + @param keyName the name of the property to delete. (This mustn't be an empty string) + @see setComponentProperty, getComponentProperty */ - virtual void anotherInstanceStarted (const String& commandLine); + void removeComponentProperty (const String& keyName) throw(); - /** Called when the operating system is trying to close the application. + /** Returns the complete set of properties that have been set for this component. - The default implementation of this method is to call quit(), but it may - be overloaded to ignore the request or do some other special behaviour - instead. For example, you might want to offer the user the chance to save - their changes before quitting, and give them the chance to cancel. + If no properties have been set, this will return a null pointer. - If you want to send a quit signal to your app, this is the correct method - to call, because it means that requests that come from the system get handled - in the same way as those from your own application code. So e.g. you'd - call this method from a "quit" item on a menu bar. + @see getComponentProperty, setComponentProperty */ - virtual void systemRequestedQuit(); + PropertySet* getComponentProperties() const throw() { return propertySet_; } - /** If any unhandled exceptions make it through to the message dispatch loop, this - callback will be triggered, in case you want to log them or do some other - type of error-handling. + /** Looks for a colour that has been registered with the given colour ID number. - If the type of exception is derived from the std::exception class, the pointer - passed-in will be valid. If the exception is of unknown type, this pointer - will be null. + If a colour has been set for this ID number using setColour(), then it is + returned. If none has been set, the method will try calling the component's + LookAndFeel class's findColour() method. If none has been registered with the + look-and-feel either, it will just return black. + + The colour IDs for various purposes are stored as enums in the components that + they are relevent to - for an example, see Slider::ColourIds, + Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. + + @see setColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour */ - virtual void unhandledException (const std::exception* e, - const String& sourceFilename, - const int lineNumber); + const Colour findColour (const int colourId, const bool inheritFromParent = false) const throw(); - /** Signals that the main message loop should stop and the application should terminate. + /** Registers a colour to be used for a particular purpose. - This isn't synchronous, it just posts a quit message to the main queue, and - when this message arrives, the message loop will stop, the shutdown() method - will be called, and the app will exit. + Changing a colour will cause a synchronous callback to the colourChanged() + method, which your component can override if it needs to do something when + colours are altered. - Note that this will cause an unconditional quit to happen, so if you need an - extra level before this, e.g. to give the user the chance to save their work - and maybe cancel the quit, you'll need to handle this in the systemRequestedQuit() - method - see that method's help for more info. + For more details about colour IDs, see the comments for findColour(). - @see MessageManager, DeletedAtShutdown + @see findColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour */ - static void quit(); - - /** Sets the value that should be returned as the application's exit code when the - app quits. + void setColour (const int colourId, const Colour& colour); - This is the value that's returned by the main() function. Normally you'd leave this - as 0 unless you want to indicate an error code. + /** If a colour has been set with setColour(), this will remove it. - @see getApplicationReturnValue + This allows you to make a colour revert to its default state. */ - void setApplicationReturnValue (const int newReturnValue) throw(); + void removeColour (const int colourId); - /** Returns the value that has been set as the application's exit code. - @see setApplicationReturnValue + /** Returns true if the specified colour ID has been explicitly set for this + component using the setColour() method. */ - int getApplicationReturnValue() const throw() { return appReturnValue; } + bool isColourSpecified (const int colourId) const throw(); - /** Returns the application's command line params. + /** This looks for any colours that have been specified for this component, + and copies them to the specified target component. */ - const String getCommandLineParameters() const throw() { return commandLineParameters; } + void copyAllExplicitColoursTo (Component& target) const throw(); - // These are used by the START_JUCE_APPLICATION() macro and aren't for public use. + /** This method is called when a colour is changed by the setColour() method. - /** @internal */ - static int main (String& commandLine, JUCEApplication* const newApp); - /** @internal */ - static int main (int argc, char* argv[], JUCEApplication* const newApp); + @see setColour, findColour + */ + virtual void colourChanged(); - /** @internal */ - static void sendUnhandledException (const std::exception* const e, - const char* const sourceFile, - const int lineNumber); + /** Returns the underlying native window handle for this component. - /** @internal */ - ApplicationCommandTarget* getNextCommandTarget(); - /** @internal */ - void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result); - /** @internal */ - void getAllCommands (Array & commands); - /** @internal */ - bool perform (const InvocationInfo& info); - /** @internal */ - void actionListenerCallback (const String& message); + This is platform-dependent and strictly for power-users only! + */ + void* getWindowHandle() const throw(); -private: + /** When created, each component is given a number to uniquely identify it. - String commandLineParameters; - int appReturnValue; - bool stillInitialising; - InterProcessLock* appLock; + The number is incremented each time a new component is created, so it's a more + unique way of identifying a component than using its memory location (which + may be reused after the component is deleted, of course). + */ + uint32 getComponentUID() const throw() { return componentUID; } - JUCEApplication (const JUCEApplication&); - const JUCEApplication& operator= (const JUCEApplication&); + juce_UseDebuggingNewOperator -public: - /** @internal */ - bool initialiseApp (String& commandLine); - /** @internal */ - static int shutdownAppAndClearUp(); -}; +private: -#endif // __JUCE_APPLICATION_JUCEHEADER__ -/********* End of inlined file: juce_Application.h *********/ + friend class ComponentPeer; + friend class InternalDragRepeater; -#endif -#ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ + static Component* currentlyFocusedComponent; + static Component* componentUnderMouse; -#endif -#ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ + String componentName_; + Component* parentComponent_; + uint32 componentUID; + Rectangle bounds_; + unsigned short numDeepMouseListeners; + Array childComponentList_; + LookAndFeel* lookAndFeel_; + MouseCursor cursor_; + ImageEffectFilter* effect_; + Image* bufferedImage_; + VoidArray* mouseListeners_; + VoidArray* keyListeners_; + VoidArray* componentListeners_; + PropertySet* propertySet_; + struct ComponentFlags + { + bool hasHeavyweightPeerFlag : 1; + bool visibleFlag : 1; + bool opaqueFlag : 1; + bool ignoresMouseClicksFlag : 1; + bool allowChildMouseClicksFlag : 1; + bool wantsFocusFlag : 1; + bool isFocusContainerFlag : 1; + bool dontFocusOnMouseClickFlag : 1; + bool alwaysOnTopFlag : 1; + bool bufferToImageFlag : 1; + bool bringToFrontOnClickFlag : 1; + bool repaintOnMouseActivityFlag : 1; + bool draggingFlag : 1; + bool mouseOverFlag : 1; + bool mouseInsideFlag : 1; + bool currentlyModalFlag : 1; + bool isDisabledFlag : 1; + bool childCompFocusedFlag : 1; +#ifdef JUCE_DEBUG + bool isInsidePaintCall : 1; #endif -#ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ - -/********* Start of inlined file: juce_ApplicationCommandManager.h *********/ -#ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ -#define __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ + }; -/********* Start of inlined file: juce_AsyncUpdater.h *********/ -#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ -#define __JUCE_ASYNCUPDATER_JUCEHEADER__ + union + { + uint32 componentFlags_; + ComponentFlags flags; + }; -/** - Has a callback method that is triggered asynchronously. + void internalMouseEnter (int x, int y, const int64 time); + void internalMouseExit (int x, int y, const int64 time); + void internalMouseDown (int x, int y); + void internalMouseUp (const int oldModifiers, int x, int y, const int64 time); + void internalMouseDrag (int x, int y, const int64 time); + void internalMouseMove (int x, int y, const int64 time); + void internalMouseWheel (const int intAmountX, const int intAmountY, const int64 time); + void internalBroughtToFront(); + void internalFocusGain (const FocusChangeType cause); + void internalFocusLoss (const FocusChangeType cause); + void internalChildFocusChange (FocusChangeType cause); + void internalModalInputAttempt(); + void internalModifierKeysChanged(); + void internalChildrenChanged(); + void internalHierarchyChanged(); + void internalUpdateMouseCursor (const bool forcedUpdate) throw(); + void sendMovedResizedMessages (const bool wasMoved, const bool wasResized); + void repaintParent() throw(); + void sendFakeMouseMove() const; + void takeKeyboardFocus (const FocusChangeType cause); + void grabFocusInternal (const FocusChangeType cause, const bool canTryParent = true); + static void giveAwayFocus(); + void sendEnablementChangeMessage(); + static void* runModalLoopCallback (void*); + static void bringModalComponentToFront(); + void subtractObscuredRegions (RectangleList& result, + const int deltaX, const int deltaY, + const Rectangle& clipRect, + const Component* const compToAvoid) const throw(); + void clipObscuredRegions (Graphics& g, const Rectangle& clipRect, + const int deltaX, const int deltaY) const throw(); - This object allows an asynchronous callback function to be triggered, for - tasks such as coalescing multiple updates into a single callback later on. + // how much of the component is not off the edges of its parents + const Rectangle getUnclippedArea() const; + void sendVisibilityChangeMessage(); - 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: + // This is included here just to cause a compile error if your code is still handling + // drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget + // class, which is easy (just make your class inherit from FileDragAndDropTarget, and + // implement its methods instead of this Component method). + virtual void filesDropped (const StringArray&, int, int) {} - /** Creates an AsyncUpdater object. */ - AsyncUpdater() throw(); + // components aren't allowed to have copy constructors, as this would mess up parent + // hierarchies. You might need to give your subclasses a private dummy constructor like + // this one to avoid compiler warnings. + Component (const Component&); - /** Destructor. + const Component& operator= (const Component&); - If there are any pending callbacks when the object is deleted, these are lost. - */ - virtual ~AsyncUpdater(); + // (dummy method to cause a deliberate compile error - if you hit this, you need to update your + // subclass to use the new parameters to keyStateChanged) + virtual void keyStateChanged() {}; - /** Causes the callback to be triggered at a later time. +protected: + /** @internal */ + virtual void internalRepaint (int x, int y, int w, int h); - This method returns immediately, having made sure that a callback - to the handleAsyncUpdate() method will occur as soon as possible. + virtual ComponentPeer* createNewPeer (int styleFlags, void* nativeWindowToAttachTo); - If an update callback is already pending but hasn't happened yet, calls - to this method will be ignored. + /** Overridden from the MessageListener parent class. - It's thread-safe to call this method from any number of threads without - needing to worry about locking. + You can override this if you really need to, but be sure to pass your unwanted messages up + to this base class implementation, as the Component class needs to send itself messages + to work properly. */ - void triggerAsyncUpdate() throw(); + void handleMessage (const Message&); +}; - /** This will stop any pending updates from happening. +#endif // __JUCE_COMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_Component.h *********/ - If called after triggerAsyncUpdate() and before the handleAsyncUpdate() - callback happens, this will cancel the handleAsyncUpdate() callback. - */ - void cancelPendingUpdate() throw(); +/********* Start of inlined file: juce_ApplicationCommandInfo.h *********/ +#ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ +#define __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ - /** If an update has been triggered and is pending, this will invoke it - synchronously. +/********* Start of inlined file: juce_ApplicationCommandID.h *********/ +#ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ +#define __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ - 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(); +/** A type used to hold the unique ID for an application command. - /** Called back to do whatever your class needs to do. + This is a numeric type, so it can be stored as an integer. - This method is called by the message thread at the next convenient time - after the triggerAsyncUpdate() method has been called. - */ - virtual void handleAsyncUpdate() = 0; + @see ApplicationCommandInfo, ApplicationCommandManager, + ApplicationCommandTarget, KeyPressMappingSet +*/ +typedef int CommandID; -private: +/** A set of general-purpose application command IDs. - class AsyncUpdaterInternal : public MessageListener - { - public: - AsyncUpdaterInternal() throw() {} - ~AsyncUpdaterInternal() {} + Because these commands are likely to be used in most apps, they're defined + here to help different apps to use the same numeric values for them. - void handleMessage (const Message&); + Of course you don't have to use these, but some of them are used internally by + Juce - e.g. the quit ID is recognised as a command by the JUCEApplication class. - AsyncUpdater* owner; + @see ApplicationCommandInfo, ApplicationCommandManager, + ApplicationCommandTarget, KeyPressMappingSet +*/ +namespace StandardApplicationCommandIDs +{ + /** This command ID should be used to send a "Quit the App" command. - private: - AsyncUpdaterInternal (const AsyncUpdaterInternal&); - const AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); - }; + This command is recognised by the JUCEApplication class, so if it is invoked + and no other ApplicationCommandTarget handles the event first, the JUCEApplication + object will catch it and call JUCEApplication::systemRequestedQuit(). + */ + static const CommandID quit = 0x1001; - AsyncUpdaterInternal internalAsyncHandler; - bool asyncMessagePending; -}; + /** The command ID that should be used to send a "Delete" command. */ + static const CommandID del = 0x1002; -#endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ -/********* End of inlined file: juce_AsyncUpdater.h *********/ + /** The command ID that should be used to send a "Cut" command. */ + static const CommandID cut = 0x1003; -/********* Start of inlined file: juce_Desktop.h *********/ -#ifndef __JUCE_DESKTOP_JUCEHEADER__ -#define __JUCE_DESKTOP_JUCEHEADER__ + /** The command ID that should be used to send a "Copy to clipboard" command. */ + static const CommandID copy = 0x1004; -/********* Start of inlined file: juce_DeletedAtShutdown.h *********/ -#ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ -#define __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ + /** The command ID that should be used to send a "Paste from clipboard" command. */ + static const CommandID paste = 0x1005; + + /** The command ID that should be used to send a "Select all" command. */ + static const CommandID selectAll = 0x1006; + + /** The command ID that should be used to send a "Deselect all" command. */ + static const CommandID deselectAll = 0x1007; +} + +#endif // __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ +/********* End of inlined file: juce_ApplicationCommandID.h *********/ /** - Classes derived from this will be automatically deleted when the application exits. + Holds information describing an application command. - After JUCEApplication::shutdown() has been called, any objects derived from - DeletedAtShutdown which are still in existence will be deleted in the reverse - order to that in which they were created. + This object is used to pass information about a particular command, such as its + name, description and other usage flags. - So if you've got a singleton and don't want to have to explicitly delete it, just - inherit from this and it'll be taken care of. + When an ApplicationCommandTarget is asked to provide information about the commands + it can perform, this is the structure gets filled-in to describe each one. + + @see ApplicationCommandTarget, ApplicationCommandTarget::getCommandInfo(), + ApplicationCommandManager */ -class JUCE_API DeletedAtShutdown +struct JUCE_API ApplicationCommandInfo { -protected: - /** Creates a DeletedAtShutdown object. */ - DeletedAtShutdown() throw(); - /** Destructor. + ApplicationCommandInfo (const CommandID commandID) throw(); - It's ok to delete these objects explicitly - it's only the ones left - dangling at the end that will be deleted automatically. + /** Sets a number of the structures values at once. + + The meanings of each of the parameters is described below, in the appropriate + member variable's description. */ - virtual ~DeletedAtShutdown(); + void setInfo (const String& shortName, + const String& description, + const String& categoryName, + const int flags) throw(); -public: - /** Deletes all extant objects. + /** An easy way to set or remove the isDisabled bit in the structure's flags field. - This shouldn't be used by applications, as it's called automatically - in the shutdown code of the JUCEApplication class. + If isActive is true, the flags member has the isDisabled bit cleared; if isActive + is false, the bit is set. */ - static void deleteAll(); - -private: - DeletedAtShutdown (const DeletedAtShutdown&); - const DeletedAtShutdown& operator= (const DeletedAtShutdown&); -}; + void setActive (const bool isActive) throw(); -#endif // __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ -/********* End of inlined file: juce_DeletedAtShutdown.h *********/ + /** An easy way to set or remove the isTicked bit in the structure's flags field. + */ + void setTicked (const bool isTicked) throw(); -/********* Start of inlined file: juce_Timer.h *********/ -#ifndef __JUCE_TIMER_JUCEHEADER__ -#define __JUCE_TIMER_JUCEHEADER__ + /** Handy method for adding a keypress to the defaultKeypresses array. -class InternalTimerThread; + This is just so you can write things like: + @code + myinfo.addDefaultKeypress (T('s'), ModifierKeys::commandModifier); + @endcode + instead of + @code + myinfo.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::commandModifier)); + @endcode + */ + void addDefaultKeypress (const int keyCode, + const ModifierKeys& modifiers) throw(); -/** - Repeatedly calls a user-defined method at a specified time interval. + /** The command's unique ID number. + */ + CommandID commandID; - A Timer's timerCallback() method will be repeatedly called at a given - interval. Initially when a Timer object is created, they will do nothing - until the startTimer() method is called, then the message thread will - start calling it back until stopTimer() is called. + /** A short name to describe the command. - The time interval isn't guaranteed to be precise to any more than maybe - 10-20ms, and the intervals may end up being much longer than requested if the - system is busy. Because it's the message thread that is doing the callbacks, - any messages that take a significant amount of time to process will block - all the timers for that period. + This should be suitable for use in menus, on buttons that trigger the command, etc. - If you need to have a single callback that is shared by multiple timers with - different frequencies, then the MultiTimer class allows you to do that - its - structure is very similar to the Timer class, but contains multiple timers - internally, each one identified by an ID number. + You can use the setInfo() method to quickly set this and some of the command's + other properties. + */ + String shortName; - @see MultiTimer -*/ -class JUCE_API Timer -{ -protected: + /** A longer description of the command. - /** Creates a Timer. + This should be suitable for use in contexts such as a KeyMappingEditorComponent or + pop-up tooltip describing what the command does. - When created, the timer is stopped, so use startTimer() to get it going. + You can use the setInfo() method to quickly set this and some of the command's + other properties. */ - Timer() throw(); + String description; - /** Creates a copy of another timer. + /** A named category that the command fits into. - Note that this timer won't be started, even if the one you're copying - is running. + You can give your commands any category you like, and these will be displayed in + contexts such as the KeyMappingEditorComponent, where the category is used to group + commands together. + + You can use the setInfo() method to quickly set this and some of the command's + other properties. */ - Timer (const Timer& other) throw(); + String categoryName; -public: + /** A list of zero or more keypresses that should be used as the default keys for + this command. - /** Destructor. */ - virtual ~Timer(); + Methods such as KeyPressMappingSet::resetToDefaultMappings() will use the keypresses in + this list to initialise the default set of key-to-command mappings. - /** The user-defined callback routine that actually gets called periodically. + @see addDefaultKeypress + */ + Array defaultKeypresses; - It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. + /** Flags describing the ways in which this command should be used. + + A bitwise-OR of these values is stored in the ApplicationCommandInfo::flags + variable. */ - virtual void timerCallback() = 0; + enum CommandFlags + { + /** Indicates that the command can't currently be performed. - /** Starts the timer and sets the length of interval required. + The ApplicationCommandTarget::getCommandInfo() method must set this flag if it's + not currently permissable to perform the command. If the flag is set, then + components that trigger the command, e.g. PopupMenu, may choose to grey-out the + command or show themselves as not being enabled. - If the timer is already started, this will reset it, so the - time between calling this method and the next timer callback - will not be less than the interval length passed in. + @see ApplicationCommandInfo::setActive + */ + isDisabled = 1 << 0, - @param intervalInMilliseconds the interval to use (any values less than 1 will be - rounded up to 1) - */ - void startTimer (const int intervalInMilliseconds) throw(); + /** Indicates that the command should have a tick next to it on a menu. - /** Stops the timer. + If your command is shown on a menu and this is set, it'll show a tick next to + it. Other components such as buttons may also use this flag to indicate that it + is a value that can be toggled, and is currently in the 'on' state. - No more callbacks will be made after this method returns. + @see ApplicationCommandInfo::setTicked + */ + isTicked = 1 << 1, - If this is called from a different thread, any callbacks that may - be currently executing may be allowed to finish before the method - returns. - */ - void stopTimer() throw(); + /** If this flag is present, then when a KeyPressMappingSet invokes the command, + it will call the command twice, once on key-down and again on key-up. - /** Checks if the timer has been started. + @see ApplicationCommandTarget::InvocationInfo + */ + wantsKeyUpDownCallbacks = 1 << 2, - @returns true if the timer is running. - */ - bool isTimerRunning() const throw() { return periodMs > 0; } + /** If this flag is present, then a KeyMappingEditorComponent will not display the + command in its list. + */ + hiddenFromKeyEditor = 1 << 3, - /** Returns the timer's interval. + /** If this flag is present, then a KeyMappingEditorComponent will display the + command in its list, but won't allow the assigned keypress to be changed. + */ + readOnlyInKeyEditor = 1 << 4, - @returns the timer's interval in milliseconds if it's running, or 0 if it's not. - */ - int getTimerInterval() const throw() { return periodMs; } + /** If this flag is present and the command is invoked from a keypress, then any + buttons or menus that are also connected to the command will not flash to + indicate that they've been triggered. + */ + dontTriggerVisualFeedback = 1 << 5 + }; -private: - friend class InternalTimerThread; - int countdownMs, periodMs; - Timer* previous; - Timer* next; + /** A bitwise-OR of the values specified in the CommandFlags enum. - const Timer& operator= (const Timer&); + You can use the setInfo() method to quickly set this and some of the command's + other properties. + */ + int flags; }; -#endif // __JUCE_TIMER_JUCEHEADER__ -/********* End of inlined file: juce_Timer.h *********/ +#endif // __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ +/********* End of inlined file: juce_ApplicationCommandInfo.h *********/ /** - Classes can implement this interface and register themselves with the Desktop class - to receive callbacks when the currently focused component changes. + A command target publishes a list of command IDs that it can perform. - @see Desktop::addFocusChangeListener, Desktop::removeFocusChangeListener -*/ -class JUCE_API FocusChangeListener -{ -public: - /** Destructor. */ - virtual ~FocusChangeListener() {} + An ApplicationCommandManager despatches commands to targets, which must be + able to provide information about what commands they can handle. - /** Callback to indicate that the currently focused component has changed. */ - virtual void globalFocusChanged (Component* focusedComponent) = 0; -}; + To create a target, you'll need to inherit from this class, implementing all of + its pure virtual methods. -/** - Describes and controls aspects of the computer's desktop. + For info about how a target is chosen to receive a command, see + ApplicationCommandManager::getFirstCommandTarget(). + @see ApplicationCommandManager, ApplicationCommandInfo */ -class JUCE_API Desktop : private DeletedAtShutdown, - private Timer, - private AsyncUpdater +class JUCE_API ApplicationCommandTarget { public: - /** There's only one dektop object, and this method will return it. - */ - static Desktop& JUCE_CALLTYPE getInstance() throw(); - - /** Returns a list of the positions of all the monitors available. + /** Creates a command target. */ + ApplicationCommandTarget(); - The first rectangle in the list will be the main monitor area. + /** Destructor. */ + virtual ~ApplicationCommandTarget(); - If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, - or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. + /** */ - const RectangleList getAllMonitorDisplayAreas (const bool clippedToWorkArea = true) const throw(); - - /** Returns the position and size of the main monitor. + struct JUCE_API InvocationInfo + { - If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, - or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. - */ - const Rectangle getMainMonitorArea (const bool clippedToWorkArea = true) const throw(); + InvocationInfo (const CommandID commandID) throw(); - /** Returns the position and size of the monitor which contains this co-ordinate. + /** The UID of the command that should be performed. */ + CommandID commandID; - If none of the monitors contains the point, this will just return the - main monitor. + /** The command's flags. - If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, - or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. - */ - const Rectangle getMonitorAreaContaining (int x, int y, const bool clippedToWorkArea = true) const throw(); + See ApplicationCommandInfo for a description of these flag values. + */ + int commandFlags; - /** Returns the mouse position. + /** The types of context in which the command might be called. */ + enum InvocationMethod + { + direct = 0, /**< The command is being invoked directly by a piece of code. */ + fromKeyPress, /**< The command is being invoked by a key-press. */ + fromMenu, /**< The command is being invoked by a menu selection. */ + fromButton /**< The command is being invoked by a button click. */ + }; - The co-ordinates are relative to the top-left of the main monitor. - */ - static void getMousePosition (int& x, int& y) throw(); + /** The type of event that triggered this command. */ + InvocationMethod invocationMethod; - /** Makes the mouse pointer jump to a given location. + /** If triggered by a keypress or menu, this will be the component that had the + keyboard focus at the time. - The co-ordinates are relative to the top-left of the main monitor. - */ - static void setMousePosition (int x, int y) throw(); + If triggered by a button, it may be set to that component, or it may be null. + */ + Component* originatingComponent; - /** Returns the last position at which a mouse button was pressed. - */ - static void getLastMouseDownPosition (int& x, int& y) throw(); + /** The keypress that was used to invoke it. - /** Returns the number of times the mouse button has been clicked since the - app started. + Note that this will be an invalid keypress if the command was invoked + by some other means than a keyboard shortcut. + */ + KeyPress keyPress; - Each mouse-down event increments this number by 1. - */ - static int getMouseButtonClickCounter() throw(); + /** True if the callback is being invoked when the key is pressed, + false if the key is being released. - /** This lets you prevent the screensaver from becoming active. + @see KeyPressMappingSet::addCommand() + */ + bool isKeyDown; - Handy if you're running some sort of presentation app where having a screensaver - appear would be annoying. + /** If the key is being released, this indicates how long it had been held + down for. - Pass false to disable the screensaver, and true to re-enable it. (Note that this - won't enable a screensaver unless the user has actually set one up). + (Only relevant if isKeyDown is false.) + */ + int millisecsSinceKeyPressed; + }; - The disablement will only happen while the Juce application is the foreground - process - if another task is running in front of it, then the screensaver will - be unaffected. + /** This must return the next target to try after this one. - @see isScreenSaverEnabled - */ - static void setScreenSaverEnabled (const bool isEnabled) throw(); + When a command is being sent, and the first target can't handle + that command, this method is used to determine the next target that should + be tried. - /** Returns true if the screensaver has not been turned off. + It may return 0 if it doesn't know of another target. - This will return the last value passed into setScreenSaverEnabled(). Note that - it won't tell you whether the user is actually using a screen saver, just - whether this app is deliberately preventing one from running. + If your target is a Component, you would usually use the findFirstTargetParentComponent() + method to return a parent component that might want to handle it. - @see setScreenSaverEnabled + @see invoke */ - static bool isScreenSaverEnabled() throw(); + virtual ApplicationCommandTarget* getNextCommandTarget() = 0; - /** Registers a MouseListener that will receive all mouse events that occur on - any component. + /** This must return a complete list of commands that this target can handle. - @see removeGlobalMouseListener + Your target should add all the command IDs that it handles to the array that is + passed-in. */ - void addGlobalMouseListener (MouseListener* const listener) throw(); - - /** Unregisters a MouseListener that was added with the addGlobalMouseListener() - method. + virtual void getAllCommands (Array & commands) = 0; - @see addGlobalMouseListener - */ - void removeGlobalMouseListener (MouseListener* const listener) throw(); + /** This must provide details about one of the commands that this target can perform. - /** Registers a MouseListener that will receive a callback whenever the focused - component changes. - */ - void addFocusChangeListener (FocusChangeListener* const listener) throw(); + This will be called with one of the command IDs that the target provided in its + getAllCommands() methods. - /** Unregisters a listener that was added with addFocusChangeListener(). */ - void removeFocusChangeListener (FocusChangeListener* const listener) throw(); + It should fill-in all appropriate fields of the ApplicationCommandInfo structure with + suitable information about the command. (The commandID field will already have been filled-in + by the caller). - /** Takes a component and makes it full-screen, removing the taskbar, dock, etc. + The easiest way to set the info is using the ApplicationCommandInfo::setInfo() method to + set all the fields at once. - The component must already be on the desktop for this method to work. It will - be resized to completely fill the screen and any extraneous taskbars, menu bars, - etc will be hidden. + If the command is currently inactive for some reason, this method must use + ApplicationCommandInfo::setActive() to make that clear, (or it should set the isDisabled + bit of the ApplicationCommandInfo::flags field). - To exit kiosk mode, just call setKioskModeComponent (0). When this is called, - the component that's currently being used will be resized back to the size - and position it was in before being put into this mode. + Any default key-presses for the command should be appended to the + ApplicationCommandInfo::defaultKeypresses field. - If allowMenusAndBars is true, things like the menu and dock (on mac) are still - allowed to pop up when the mouse moves onto them. If this is false, it'll try - to hide as much on-screen paraphenalia as possible. + Note that if you change something that affects the status of the commands + that would be returned by this method (e.g. something that makes some commands + active or inactive), you should call ApplicationCommandManager::commandStatusChanged() + to cause the manager to refresh its status. */ - void setKioskModeComponent (Component* componentToUse, - const bool allowMenusAndBars = true); + virtual void getCommandInfo (const CommandID commandID, + ApplicationCommandInfo& result) = 0; - /** Returns the component that is currently being used in kiosk-mode. + /** This must actually perform the specified command. - This is the component that was last set by setKioskModeComponent(). If none - has been set, this returns 0. - */ - Component* getKioskModeComponent() const { return kioskModeComponent; } + If this target is able to perform the command specified by the commandID field of the + InvocationInfo structure, then it should do so, and must return true. - /** Returns the number of components that are currently active as top-level - desktop windows. + If it can't handle this command, it should return false, which tells the caller to pass + the command on to the next target in line. - @see getComponent, Component::addToDesktop + @see invoke, ApplicationCommandManager::invoke */ - int getNumComponents() const throw(); + virtual bool perform (const InvocationInfo& info) = 0; - /** Returns one of the top-level desktop window components. + /** Makes this target invoke a command. - The index is from 0 to getNumComponents() - 1. This could return 0 if the - index is out-of-range. + Your code can call this method to invoke a command on this target, but normally + you'd call it indirectly via ApplicationCommandManager::invoke() or + ApplicationCommandManager::invokeDirectly(). - @see getNumComponents, Component::addToDesktop - */ - Component* getComponent (const int index) const throw(); + If this target can perform the given command, it will call its perform() method to + do so. If not, then getNextCommandTarget() will be used to determine the next target + to try, and the command will be passed along to it. - /** Finds the component at a given screen location. + @param invocationInfo this must be correctly filled-in, describing the context for + the invocation. + @param asynchronously if false, the command will be performed before this method returns. + If true, a message will be posted so that the command will be performed + later on the message thread, and this method will return immediately. + @see perform, ApplicationCommandManager::invoke + */ + bool invoke (const InvocationInfo& invocationInfo, + const bool asynchronously); - This will drill down into top-level windows to find the child component at - the given position. + /** Invokes a given command directly on this target. - Returns 0 if the co-ordinates are inside a non-Juce window. + This is just an easy way to call invoke() without having to fill out the InvocationInfo + structure. */ - Component* findComponentAt (const int screenX, - const int screenY) const; - - juce_UseDebuggingNewOperator + bool invokeDirectly (const CommandID commandID, + const bool asynchronously); - /** Tells this object to refresh its idea of what the screen resolution is. + /** Searches this target and all subsequent ones for the first one that can handle + the specified command. - (Called internally by the native code). + This will use getNextCommandTarget() to determine the chain of targets to try + after this one. */ - void refreshMonitorSizes() throw(); + ApplicationCommandTarget* getTargetForCommand (const CommandID commandID); - /** True if the OS supports semitransparent windows */ - static bool canUseSemiTransparentWindows() throw(); + /** Checks whether this command can currently be performed by this target. -private: + This will return true only if a call to getCommandInfo() doesn't set the + isDisabled flag to indicate that the command is inactive. + */ + bool isCommandActive (const CommandID commandID); - friend class Component; - friend class ComponentPeer; - SortedSet mouseListeners, focusListeners; - VoidArray desktopComponents; + /** If this object is a Component, this method will seach upwards in its current + UI hierarchy for the next parent component that implements the + ApplicationCommandTarget class. - friend class DeletedAtShutdown; - friend class TopLevelWindowManager; - Desktop() throw(); - ~Desktop() throw(); + If your target is a Component, this is a very handy method to use in your + getNextCommandTarget() implementation. + */ + ApplicationCommandTarget* findFirstTargetParentComponent(); - Array monitorCoordsClipped, monitorCoordsUnclipped; - int lastMouseX, lastMouseY; + juce_UseDebuggingNewOperator - Component* kioskModeComponent; - Rectangle kioskComponentOriginalBounds; +private: + // (for async invocation of commands) + class CommandTargetMessageInvoker : public MessageListener + { + public: + CommandTargetMessageInvoker (ApplicationCommandTarget* const owner); + ~CommandTargetMessageInvoker(); - void timerCallback(); - void sendMouseMove(); - void resetTimer() throw(); + void handleMessage (const Message& message); - int getNumDisplayMonitors() const throw(); - const Rectangle getDisplayMonitorCoordinates (const int index, const bool clippedToWorkArea) const throw(); + private: + ApplicationCommandTarget* const owner; - void addDesktopComponent (Component* const c) throw(); - void removeDesktopComponent (Component* const c) throw(); - void componentBroughtToFront (Component* const c) throw(); + CommandTargetMessageInvoker (const CommandTargetMessageInvoker&); + const CommandTargetMessageInvoker& operator= (const CommandTargetMessageInvoker&); + }; - void triggerFocusCallback() throw(); - void handleAsyncUpdate(); + CommandTargetMessageInvoker* messageInvoker; - Desktop (const Desktop&); - const Desktop& operator= (const Desktop&); + friend class CommandTargetMessageInvoker; + bool tryToInvoke (const InvocationInfo& info, const bool async); + + ApplicationCommandTarget (const ApplicationCommandTarget&); + const ApplicationCommandTarget& operator= (const ApplicationCommandTarget&); }; -#endif // __JUCE_DESKTOP_JUCEHEADER__ -/********* End of inlined file: juce_Desktop.h *********/ +#endif // __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ +/********* End of inlined file: juce_ApplicationCommandTarget.h *********/ -class KeyPressMappingSet; -class ApplicationCommandManagerListener; +/********* Start of inlined file: juce_ActionListener.h *********/ +#ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ +#define __JUCE_ACTIONLISTENER_JUCEHEADER__ /** - One of these objects holds a list of all the commands your app can perform, - and despatches these commands when needed. + Receives callbacks to indicate that some kind of event has occurred. - Application commands are a good way to trigger actions in your app, e.g. "Quit", - "Copy", "Paste", etc. Menus, buttons and keypresses can all be given commands - to invoke automatically, which means you don't have to handle the result of a menu - or button click manually. Commands are despatched to ApplicationCommandTarget objects - which can choose which events they want to handle. + Used by various classes, e.g. buttons when they are pressed, to tell listeners + about something that's happened. - This architecture also allows for nested ApplicationCommandTargets, so that for example - you could have two different objects, one inside the other, both of which can respond to - a "delete" command. Depending on which one has focus, the command will be sent to the - appropriate place, regardless of whether it was triggered by a menu, keypress or some other - method. + @see ActionListenerList, ActionBroadcaster, ChangeListener +*/ +class JUCE_API ActionListener +{ +public: + /** Destructor. */ + virtual ~ActionListener() {} - To set up your app to use commands, you'll need to do the following: + /** Overridden by your subclass to receive the callback. - - Create a global ApplicationCommandManager to hold the list of all possible - commands. (This will also manage a set of key-mappings for them). + @param message the string that was specified when the event was triggered + by a call to ActionListenerList::sendActionMessage() + */ + virtual void actionListenerCallback (const String& message) = 0; +}; - - Make some of your UI components (or other objects) inherit from ApplicationCommandTarget. - This allows the object to provide a list of commands that it can perform, and - to handle them. +#endif // __JUCE_ACTIONLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_ActionListener.h *********/ - - Register each type of command using ApplicationCommandManager::registerAllCommandsForTarget(), - or ApplicationCommandManager::registerCommand(). +/** + An instance of this class is used to specify initialisation and shutdown + code for the application. - - If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings() - method to access the key-mapper object, which you will need to register as a key-listener - in whatever top-level component you're using. See the KeyPressMappingSet class for more help - about setting this up. + An application that wants to run in the JUCE framework needs to declare a + subclass of JUCEApplication and implement its various pure virtual methods. - - Use methods such as PopupMenu::addCommandItem() or Button::setCommandToTrigger() to - cause these commands to be invoked automatically. + It then needs to use the START_JUCE_APPLICATION macro somewhere in a cpp file + to declare an instance of this class and generate a suitable platform-specific + main() function. - - Commands can be invoked directly by your code using ApplicationCommandManager::invokeDirectly(). + e.g. @code + class MyJUCEApp : public JUCEApplication + { + // NEVER put objects inside a JUCEApplication class - only use pointers to + // objects, which you must create in the initialise() method. + MyApplicationWindow* myMainWindow; - When a command is invoked, the ApplicationCommandManager will try to choose the best - ApplicationCommandTarget to receive the specified command. To do this it will use the - current keyboard focus to see which component might be interested, and will search the - component hierarchy for those that also implement the ApplicationCommandTarget interface. - If an ApplicationCommandTarget isn't interested in the command that is being invoked, then - the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget() - method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns 0. At this - point if the command still hasn't been performed, it will be passed to the current - JUCEApplication object (which is itself an ApplicationCommandTarget). + public: + MyJUCEApp() + : myMainWindow (0) + { + // never create any Juce objects in the constructor - do all your initialisation + // in the initialise() method. + } - To exert some custom control over which ApplicationCommandTarget is chosen to invoke a command, - you can override the ApplicationCommandManager::getFirstCommandTarget() method and choose - the object yourself. + ~MyJUCEApp() + { + // all your shutdown code must have already been done in the shutdown() method - + // nothing should happen in this destructor. + } - @see ApplicationCommandTarget, ApplicationCommandInfo -*/ -class JUCE_API ApplicationCommandManager : private AsyncUpdater, - private FocusChangeListener -{ -public: + void initialise (const String& commandLine) + { + myMainWindow = new MyApplicationWindow(); + myMainWindow->setBounds (100, 100, 400, 500); + myMainWindow->setVisible (true); + } - /** Creates an ApplicationCommandManager. + void shutdown() + { + delete myMainWindow; + } - Once created, you'll need to register all your app's commands with it, using - ApplicationCommandManager::registerAllCommandsForTarget() or - ApplicationCommandManager::registerCommand(). - */ - ApplicationCommandManager(); + const String getApplicationName() + { + return T("Super JUCE-o-matic"); + } - /** Destructor. + const String getApplicationVersion() + { + return T("1.0"); + } + }; - Make sure that you don't delete this if pointers to it are still being used by - objects such as PopupMenus or Buttons. - */ - virtual ~ApplicationCommandManager(); + // this creates wrapper code to actually launch the app properly. + START_JUCE_APPLICATION (MyJUCEApp) + @endcode - /** Clears the current list of all commands. + Because this object will be created before Juce has properly initialised, you must + NEVER add any member variable objects that will be automatically constructed. Likewise + don't put ANY code in the constructor that could call Juce functions. Any objects that + you want to add to the class must be pointers, which you should instantiate during the + initialise() method, and delete in the shutdown() method. - Note that this will also clear the contents of the KeyPressMappingSet. - */ - void clearCommands(); + @see MessageManager, DeletedAtShutdown +*/ +class JUCE_API JUCEApplication : public ApplicationCommandTarget, + private ActionListener +{ +protected: - /** Adds a command to the list of registered commands. + /** Constructs a JUCE app object. - @see registerAllCommandsForTarget + If subclasses implement a constructor or destructor, they shouldn't call any + JUCE code in there - put your startup/shutdown code in initialise() and + shutdown() instead. */ - void registerCommand (const ApplicationCommandInfo& newCommand); - - /** Adds all the commands that this target publishes to the manager's list. + JUCEApplication(); - This will use ApplicationCommandTarget::getAllCommands() and ApplicationCommandTarget::getCommandInfo() - to get details about all the commands that this target can do, and will call - registerCommand() to add each one to the manger's list. +public: + /** Destructor. - @see registerCommand + If subclasses implement a constructor or destructor, they shouldn't call any + JUCE code in there - put your startup/shutdown code in initialise() and + shutdown() instead. */ - void registerAllCommandsForTarget (ApplicationCommandTarget* target); + virtual ~JUCEApplication(); - /** Removes the command with a specified ID. + /** Returns the global instance of the application object being run. */ + static JUCEApplication* getInstance() throw(); - Note that this will also remove any key mappings that are mapped to the command. - */ - void removeCommand (const CommandID commandID); + /** Called when the application starts. - /** This should be called to tell the manager that one of its registered commands may have changed - its active status. + This will be called once to let the application do whatever initialisation + it needs, create its windows, etc. - Because the command manager only finds out whether a command is active or inactive by querying - the current ApplicationCommandTarget, this is used to tell it that things may have changed. It - allows things like buttons to update their enablement, etc. + After the method returns, the normal event-dispatch loop will be run, + until the quit() method is called, at which point the shutdown() + method will be called to let the application clear up anything it needs + to delete. - This method will cause an asynchronous call to ApplicationCommandManagerListener::applicationCommandListChanged() - for any registered listeners. + If during the initialise() method, the application decides not to start-up + after all, it can just call the quit() method and the event loop won't be run. + + @param commandLineParameters the line passed in does not include the + name of the executable, just the parameter list. + @see shutdown, quit */ - void commandStatusChanged(); + virtual void initialise (const String& commandLineParameters) = 0; - /** Returns the number of commands that have been registered. + /** Returns true if the application hasn't yet completed its initialise() method + and entered the main event loop. - @see registerCommand + This is handy for things like splash screens to know when the app's up-and-running + properly. */ - int getNumCommands() const throw() { return commands.size(); } + bool isInitialising() const throw(); - /** Returns the details about one of the registered commands. + /* Called to allow the application to clear up before exiting. - The index is between 0 and (getNumCommands() - 1). - */ - const ApplicationCommandInfo* getCommandForIndex (const int index) const throw() { return commands [index]; } + After JUCEApplication::quit() has been called, the event-dispatch loop will + terminate, and this method will get called to allow the app to sort itself + out. - /** Returns the details about a given command ID. + Be careful that nothing happens in this method that might rely on messages + being sent, or any kind of window activity, because the message loop is no + longer running at this point. - This will search the list of registered commands for one with the given command - ID number, and return its associated info. If no matching command is found, this - will return 0. + @see DeletedAtShutdown */ - const ApplicationCommandInfo* getCommandForID (const CommandID commandID) const throw(); + virtual void shutdown() = 0; - /** Returns the name field for a command. + /** Returns the application's name. - An empty string is returned if no command with this ID has been registered. - @see getDescriptionOfCommand + An application must implement this to name itself. */ - const String getNameOfCommand (const CommandID commandID) const throw(); - - /** Returns the description field for a command. + virtual const String getApplicationName() = 0; - An empty string is returned if no command with this ID has been registered. If the - command has no description, this will return its short name field instead. + /** Returns the application's version number. - @see getNameOfCommand + An application can implement this to give itself a version. + (The default implementation of this just returns an empty string). */ - const String getDescriptionOfCommand (const CommandID commandID) const throw(); + virtual const String getApplicationVersion(); - /** Returns the list of categories. + /** Checks whether multiple instances of the app are allowed. - This will go through all registered commands, and return a list of all the distict - categoryName values from their ApplicationCommandInfo structure. + If you application class returns true for this, more than one instance is + permitted to run (except on the Mac where this isn't possible). - @see getCommandsInCategory() + If it's false, the second instance won't start, but it you will still get a + callback to anotherInstanceStarted() to tell you about this - which + gives you a chance to react to what the user was trying to do. */ - const StringArray getCommandCategories() const throw(); + virtual bool moreThanOneInstanceAllowed(); - /** Returns a list of all the command UIDs in a particular category. + /** Indicates that the user has tried to start up another instance of the app. - @see getCommandCategories() + This will get called even if moreThanOneInstanceAllowed() is false. */ - const Array getCommandsInCategory (const String& categoryName) const throw(); + virtual void anotherInstanceStarted (const String& commandLine); - /** Returns the manager's internal set of key mappings. + /** Called when the operating system is trying to close the application. - This object can be used to edit the keypresses. To actually link this object up - to invoke commands when a key is pressed, see the comments for the KeyPressMappingSet - class. + The default implementation of this method is to call quit(), but it may + be overloaded to ignore the request or do some other special behaviour + instead. For example, you might want to offer the user the chance to save + their changes before quitting, and give them the chance to cancel. - @see KeyPressMappingSet + If you want to send a quit signal to your app, this is the correct method + to call, because it means that requests that come from the system get handled + in the same way as those from your own application code. So e.g. you'd + call this method from a "quit" item on a menu bar. */ - KeyPressMappingSet* getKeyMappings() const throw() { return keyMappings; } + virtual void systemRequestedQuit(); - /** Invokes the given command directly, sending it to the default target. + /** If any unhandled exceptions make it through to the message dispatch loop, this + callback will be triggered, in case you want to log them or do some other + type of error-handling. - This is just an easy way to call invoke() without having to fill out the InvocationInfo - structure. + If the type of exception is derived from the std::exception class, the pointer + passed-in will be valid. If the exception is of unknown type, this pointer + will be null. */ - bool invokeDirectly (const CommandID commandID, - const bool asynchronously); + virtual void unhandledException (const std::exception* e, + const String& sourceFilename, + const int lineNumber); - /** Sends a command to the default target. + /** Signals that the main message loop should stop and the application should terminate. - This will choose a target using getFirstCommandTarget(), and send the specified command - to it using the ApplicationCommandTarget::invoke() method. This means that if the - first target can't handle the command, it will be passed on to targets further down the - chain (see ApplicationCommandTarget::invoke() for more info). + This isn't synchronous, it just posts a quit message to the main queue, and + when this message arrives, the message loop will stop, the shutdown() method + will be called, and the app will exit. - @param invocationInfo this must be correctly filled-in, describing the context for - the invocation. - @param asynchronously if false, the command will be performed before this method returns. - If true, a message will be posted so that the command will be performed - later on the message thread, and this method will return immediately. + Note that this will cause an unconditional quit to happen, so if you need an + extra level before this, e.g. to give the user the chance to save their work + and maybe cancel the quit, you'll need to handle this in the systemRequestedQuit() + method - see that method's help for more info. - @see ApplicationCommandTarget::invoke + @see MessageManager, DeletedAtShutdown */ - bool invoke (const ApplicationCommandTarget::InvocationInfo& invocationInfo, - const bool asynchronously); - - /** Chooses the ApplicationCommandTarget to which a command should be sent. - - Whenever the manager needs to know which target a command should be sent to, it calls - this method to determine the first one to try. - - By default, this method will return the target that was set by calling setFirstCommandTarget(). - If no target is set, it will return the result of findDefaultComponentTarget(). + static void quit(); - If you need to make sure all commands go via your own custom target, then you can - either use setFirstCommandTarget() to specify a single target, or override this method - if you need more complex logic to choose one. + /** Sets the value that should be returned as the application's exit code when the + app quits. - It may return 0 if no targets are available. + This is the value that's returned by the main() function. Normally you'd leave this + as 0 unless you want to indicate an error code. - @see getTargetForCommand, invoke, invokeDirectly + @see getApplicationReturnValue */ - virtual ApplicationCommandTarget* getFirstCommandTarget (const CommandID commandID); - - /** Sets a target to be returned by getFirstCommandTarget(). - - If this is set to 0, then getFirstCommandTarget() will by default return the - result of findDefaultComponentTarget(). + void setApplicationReturnValue (const int newReturnValue) throw(); - If you use this to set a target, make sure you call setFirstCommandTarget (0) before - deleting the target object. + /** Returns the value that has been set as the application's exit code. + @see setApplicationReturnValue */ - void setFirstCommandTarget (ApplicationCommandTarget* const newTarget) throw(); - - /** Tries to find the best target to use to perform a given command. + int getApplicationReturnValue() const throw() { return appReturnValue; } - This will call getFirstCommandTarget() to find the preferred target, and will - check whether that target can handle the given command. If it can't, then it'll use - ApplicationCommandTarget::getNextCommandTarget() to find the next one to try, and - so on until no more are available. + /** Returns the application's command line params. + */ + const String getCommandLineParameters() const throw() { return commandLineParameters; } - If no targets are found that can perform the command, this method will return 0. + // These are used by the START_JUCE_APPLICATION() macro and aren't for public use. - If a target is found, then it will get the target to fill-in the upToDateInfo - structure with the latest info about that command, so that the caller can see - whether the command is disabled, ticked, etc. - */ - ApplicationCommandTarget* getTargetForCommand (const CommandID commandID, - ApplicationCommandInfo& upToDateInfo); + /** @internal */ + static int main (String& commandLine, JUCEApplication* const newApp); + /** @internal */ + static int main (int argc, char* argv[], JUCEApplication* const newApp); - /** Registers a listener that will be called when various events occur. */ - void addListener (ApplicationCommandManagerListener* const listener) throw(); + /** @internal */ + static void sendUnhandledException (const std::exception* const e, + const char* const sourceFile, + const int lineNumber); - /** Deregisters a previously-added listener. */ - void removeListener (ApplicationCommandManagerListener* const listener) throw(); + /** @internal */ + ApplicationCommandTarget* getNextCommandTarget(); + /** @internal */ + void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result); + /** @internal */ + void getAllCommands (Array & commands); + /** @internal */ + bool perform (const InvocationInfo& info); + /** @internal */ + void actionListenerCallback (const String& message); - /** Looks for a suitable command target based on which Components have the keyboard focus. +private: - This is used by the default implementation of ApplicationCommandTarget::getFirstCommandTarget(), - but is exposed here in case it's useful. + String commandLineParameters; + int appReturnValue; + bool stillInitialising; + InterProcessLock* appLock; - It tries to pick the best ApplicationCommandTarget by looking at focused components, top level - windows, etc., and using the findTargetForComponent() method. - */ - static ApplicationCommandTarget* findDefaultComponentTarget(); + JUCEApplication (const JUCEApplication&); + const JUCEApplication& operator= (const JUCEApplication&); - /** Examines this component and all its parents in turn, looking for the first one - which is a ApplicationCommandTarget. +public: + /** @internal */ + bool initialiseApp (String& commandLine); + /** @internal */ + static int shutdownAppAndClearUp(); +}; - Returns the first ApplicationCommandTarget that it finds, or 0 if none of them implement - that class. - */ - static ApplicationCommandTarget* findTargetForComponent (Component* component); +#endif // __JUCE_APPLICATION_JUCEHEADER__ +/********* End of inlined file: juce_Application.h *********/ - juce_UseDebuggingNewOperator +#endif +#ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ -private: +#endif +#ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ - OwnedArray commands; - SortedSet listeners; - KeyPressMappingSet* keyMappings; - ApplicationCommandTarget* firstTarget; +#endif +#ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ - void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) const; - void handleAsyncUpdate(); - void globalFocusChanged (Component*); +/********* Start of inlined file: juce_ApplicationCommandManager.h *********/ +#ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ +#define __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ - // xxx this is just here to cause a compile error in old code that hasn't been changed to use the new - // version of this method. - virtual short getFirstCommandTarget() { return 0; } -}; +/********* Start of inlined file: juce_AsyncUpdater.h *********/ +#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ +#define __JUCE_ASYNCUPDATER_JUCEHEADER__ /** - A listener that receives callbacks from an ApplicationCommandManager when - commands are invoked or the command list is changed. + Has a callback method that is triggered asynchronously. - @see ApplicationCommandManager::addListener, ApplicationCommandManager::removeListener + 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 ApplicationCommandManagerListener +class JUCE_API AsyncUpdater { public: - /** Destructor. */ - virtual ~ApplicationCommandManagerListener() {} + /** Creates an AsyncUpdater object. */ + AsyncUpdater() throw(); - /** Called when an app command is about to be invoked. */ - virtual void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) = 0; - - /** Called when commands are registered or deregistered from the - command manager, or when commands are made active or inactive. + /** Destructor. - Note that if you're using this to watch for changes to whether a command is disabled, - you'll need to make sure that ApplicationCommandManager::commandStatusChanged() is called - whenever the status of your command might have changed. + If there are any pending callbacks when the object is deleted, these are lost. */ - virtual void applicationCommandListChanged() = 0; -}; - -#endif // __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_ApplicationCommandManager.h *********/ - -#endif -#ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ - -#endif -#ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ - -/********* Start of inlined file: juce_ApplicationProperties.h *********/ -#ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ -#define __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ - -/********* Start of inlined file: juce_PropertiesFile.h *********/ -#ifndef __JUCE_PROPERTIESFILE_JUCEHEADER__ -#define __JUCE_PROPERTIESFILE_JUCEHEADER__ - -/** Wrapper on a file that stores a list of key/value data pairs. - - Useful for storing application settings, etc. See the PropertySet class for - the interfaces that read and write values. + virtual ~AsyncUpdater(); - Not designed for very large amounts of data, as it keeps all the values in - memory and writes them out to disk lazily when they are changed. + /** Causes the callback to be triggered at a later time. - Because this class derives from ChangeBroadcaster, ChangeListeners can be registered - with it, and these will be signalled when a value changes. + This method returns immediately, having made sure that a callback + to the handleAsyncUpdate() method will occur as soon as possible. - @see PropertySet -*/ -class JUCE_API PropertiesFile : public PropertySet, - public ChangeBroadcaster, - private Timer -{ -public: + If an update callback is already pending but hasn't happened yet, calls + to this method will be ignored. - enum FileFormatOptions - { - ignoreCaseOfKeyNames = 1, - storeAsBinary = 2, - storeAsCompressedBinary = 4, - storeAsXML = 8 - }; + It's thread-safe to call this method from any number of threads without + needing to worry about locking. + */ + void triggerAsyncUpdate() throw(); - /** - Creates a PropertiesFile object. + /** This will stop any pending updates from happening. - @param file the file to use - @param millisecondsBeforeSaving if this is zero or greater, then after a value - is changed, the object will wait for this amount - of time and then save the file. If zero, the file - will be written to disk immediately on being changed - (which might be slow, as it'll re-write synchronously - each time a value-change method is called). If it is - less than zero, the file won't be saved until - save() or saveIfNeeded() are explicitly called. - @param options a combination of the flags in the FileFormatOptions - enum, which specify the type of file to save, and other - options. + If called after triggerAsyncUpdate() and before the handleAsyncUpdate() + callback happens, this will cancel the handleAsyncUpdate() callback. */ - PropertiesFile (const File& file, - const int millisecondsBeforeSaving, - const int options) throw(); + void cancelPendingUpdate() throw(); - /** Destructor. + /** If an update has been triggered and is pending, this will invoke it + synchronously. - When deleted, the file will first call saveIfNeeded() to flush any changes to disk. + 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. */ - ~PropertiesFile(); - - /** This will flush all the values to disk if they've changed since the last - time they were saved. + void handleUpdateNowIfNeeded(); - Returns false if it fails to write to the file for some reason (maybe because - it's read-only or the directory doesn't exist or something). + /** Called back to do whatever your class needs to do. - @see save + This method is called by the message thread at the next convenient time + after the triggerAsyncUpdate() method has been called. */ - bool saveIfNeeded(); + virtual void handleAsyncUpdate() = 0; - /** This will force a write-to-disk of the current values, regardless of whether - anything has changed since the last save. +private: - Returns false if it fails to write to the file for some reason (maybe because - it's read-only or the directory doesn't exist or something). + class AsyncUpdaterInternal : public MessageListener + { + public: + AsyncUpdaterInternal() throw() {} + ~AsyncUpdaterInternal() {} - @see saveIfNeeded - */ - bool save(); + void handleMessage (const Message&); - /** Returns true if the properties have been altered since the last time they were - saved. - */ - bool needsToBeSaved() const throw(); + AsyncUpdater* owner; - /** Returns the file that's being used. */ - const File getFile() const throw(); + private: + AsyncUpdaterInternal (const AsyncUpdaterInternal&); + const AsyncUpdaterInternal& operator= (const AsyncUpdaterInternal&); + }; - /** Handy utility to create a properties file in whatever the standard OS-specific - location is for these things. + AsyncUpdaterInternal internalAsyncHandler; + bool asyncMessagePending; +}; - This uses getDefaultAppSettingsFile() to decide what file to create, then - creates a PropertiesFile object with the specified properties. See - getDefaultAppSettingsFile() and the class's constructor for descriptions of - what the parameters do. +#endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ +/********* End of inlined file: juce_AsyncUpdater.h *********/ - @see getDefaultAppSettingsFile - */ - static PropertiesFile* createDefaultAppPropertiesFile (const String& applicationName, - const String& fileNameSuffix, - const String& folderName, - const bool commonToAllUsers, - const int millisecondsBeforeSaving, - const int propertiesFileOptions); +/********* Start of inlined file: juce_Desktop.h *********/ +#ifndef __JUCE_DESKTOP_JUCEHEADER__ +#define __JUCE_DESKTOP_JUCEHEADER__ - /** Handy utility to choose a file in the standard OS-dependent location for application - settings files. +/********* Start of inlined file: juce_DeletedAtShutdown.h *********/ +#ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ +#define __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ - So on a Mac, this will return a file called: - ~/Library/Preferences/[folderName]/[applicationName].[fileNameSuffix] +/** + Classes derived from this will be automatically deleted when the application exits. - On Windows it'll return something like: - C:\\Documents and Settings\\username\\Application Data\\[folderName]\\[applicationName].[fileNameSuffix] + After JUCEApplication::shutdown() has been called, any objects derived from + DeletedAtShutdown which are still in existence will be deleted in the reverse + order to that in which they were created. - On Linux it'll return - ~/.[folderName]/[applicationName].[fileNameSuffix] + So if you've got a singleton and don't want to have to explicitly delete it, just + inherit from this and it'll be taken care of. +*/ +class JUCE_API DeletedAtShutdown +{ +protected: + /** Creates a DeletedAtShutdown object. */ + DeletedAtShutdown() throw(); - If you pass an empty string as the folder name, it'll use the app name for this (or - omit the folder name on the Mac). + /** Destructor. - If commonToAllUsers is true, then this will return the same file for all users of the - computer, regardless of the current user. If it is false, the file will be specific to - only the current user. Use this to choose whether you're saving settings that are common - or user-specific. + It's ok to delete these objects explicitly - it's only the ones left + dangling at the end that will be deleted automatically. */ - static const File getDefaultAppSettingsFile (const String& applicationName, - const String& fileNameSuffix, - const String& folderName, - const bool commonToAllUsers); + virtual ~DeletedAtShutdown(); - juce_UseDebuggingNewOperator +public: + /** Deletes all extant objects. -protected: - virtual void propertyChanged(); + This shouldn't be used by applications, as it's called automatically + in the shutdown code of the JUCEApplication class. + */ + static void deleteAll(); private: + DeletedAtShutdown (const DeletedAtShutdown&); + const DeletedAtShutdown& operator= (const DeletedAtShutdown&); +}; - File file; - int timerInterval; - const int options; - bool needsWriting; - - void timerCallback(); +#endif // __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ +/********* End of inlined file: juce_DeletedAtShutdown.h *********/ - PropertiesFile (const PropertiesFile&); - const PropertiesFile& operator= (const PropertiesFile&); -}; +/********* Start of inlined file: juce_Timer.h *********/ +#ifndef __JUCE_TIMER_JUCEHEADER__ +#define __JUCE_TIMER_JUCEHEADER__ -#endif // __JUCE_PROPERTIESFILE_JUCEHEADER__ -/********* End of inlined file: juce_PropertiesFile.h *********/ +class InternalTimerThread; /** - Manages a collection of properties. - - This is a slightly higher-level wrapper for PropertiesFile, which can be used - as a singleton. + Repeatedly calls a user-defined method at a specified time interval. - It holds two different PropertiesFile objects internally, one for user-specific - settings (stored in your user directory), and one for settings that are common to - all users (stored in a folder accessible to all users). + A Timer's timerCallback() method will be repeatedly called at a given + interval. Initially when a Timer object is created, they will do nothing + until the startTimer() method is called, then the message thread will + start calling it back until stopTimer() is called. - The class manages the creation of these files on-demand, allowing access via the - getUserSettings() and getCommonSettings() methods. It also has a few handy - methods like testWriteAccess() to check that the files can be saved. + The time interval isn't guaranteed to be precise to any more than maybe + 10-20ms, and the intervals may end up being much longer than requested if the + system is busy. Because it's the message thread that is doing the callbacks, + any messages that take a significant amount of time to process will block + all the timers for that period. - If you're using one of these as a singleton, then your app's start-up code should - first of all call setStorageParameters() to tell it the parameters to use to create - the properties files. + If you need to have a single callback that is shared by multiple timers with + different frequencies, then the MultiTimer class allows you to do that - its + structure is very similar to the Timer class, but contains multiple timers + internally, each one identified by an ID number. - @see PropertiesFile + @see MultiTimer */ -class JUCE_API ApplicationProperties : public DeletedAtShutdown +class JUCE_API Timer { -public: - - /** - Creates an ApplicationProperties object. +protected: - Before using it, you must call setStorageParameters() to give it the info - it needs to create the property files. - */ - ApplicationProperties() throw(); + /** Creates a Timer. - /** Destructor. + When created, the timer is stopped, so use startTimer() to get it going. */ - ~ApplicationProperties(); - - juce_DeclareSingleton (ApplicationProperties, false) + Timer() throw(); - /** Gives the object the information it needs to create the appropriate properties files. + /** Creates a copy of another timer. - See the comments for PropertiesFile::createDefaultAppPropertiesFile() for more - info about how these parameters are used. + Note that this timer won't be started, even if the one you're copying + is running. */ - void setStorageParameters (const String& applicationName, - const String& fileNameSuffix, - const String& folderName, - const int millisecondsBeforeSaving, - const int propertiesFileOptions) throw(); + Timer (const Timer& other) throw(); - /** Tests whether the files can be successfully written to, and can show - an error message if not. +public: - Returns true if none of the tests fail. + /** Destructor. */ + virtual ~Timer(); - @param testUserSettings if true, the user settings file will be tested - @param testCommonSettings if true, the common settings file will be tested - @param showWarningDialogOnFailure if true, the method will show a helpful error - message box if either of the tests fail - */ - bool testWriteAccess (const bool testUserSettings, - const bool testCommonSettings, - const bool showWarningDialogOnFailure); + /** The user-defined callback routine that actually gets called periodically. - /** Returns the user settings file. + It's perfectly ok to call startTimer() or stopTimer() from within this + callback to change the subsequent intervals. + */ + virtual void timerCallback() = 0; - The first time this is called, it will create and load the properties file. + /** Starts the timer and sets the length of interval required. - Note that when you search the user PropertiesFile for a value that it doesn't contain, - the common settings are used as a second-chance place to look. This is done via the - PropertySet::setFallbackPropertySet() method - by default the common settings are set - to the fallback for the user settings. + If the timer is already started, this will reset it, so the + time between calling this method and the next timer callback + will not be less than the interval length passed in. - @see getCommonSettings + @param intervalInMilliseconds the interval to use (any values less than 1 will be + rounded up to 1) */ - PropertiesFile* getUserSettings() throw(); + void startTimer (const int intervalInMilliseconds) throw(); - /** Returns the common settings file. + /** Stops the timer. - The first time this is called, it will create and load the properties file. + No more callbacks will be made after this method returns. - @param returnUserPropsIfReadOnly if this is true, and the common properties file is - read-only (e.g. because the user doesn't have permission to write - to shared files), then this will return the user settings instead, - (like getUserSettings() would do). This is handy if you'd like to - write a value to the common settings, but if that's no possible, - then you'd rather write to the user settings than none at all. - If returnUserPropsIfReadOnly is false, this method will always return - the common settings, even if any changes to them can't be saved. - @see getUserSettings + If this is called from a different thread, any callbacks that may + be currently executing may be allowed to finish before the method + returns. */ - PropertiesFile* getCommonSettings (const bool returnUserPropsIfReadOnly) throw(); + void stopTimer() throw(); - /** Saves both files if they need to be saved. + /** Checks if the timer has been started. - @see PropertiesFile::saveIfNeeded + @returns true if the timer is running. */ - bool saveIfNeeded(); + bool isTimerRunning() const throw() { return periodMs > 0; } - /** Flushes and closes both files if they are open. + /** Returns the timer's interval. - This flushes any pending changes to disk with PropertiesFile::saveIfNeeded() - and closes both files. They will then be re-opened the next time getUserSettings() - or getCommonSettings() is called. + @returns the timer's interval in milliseconds if it's running, or 0 if it's not. */ - void closeFiles(); - - juce_UseDebuggingNewOperator + int getTimerInterval() const throw() { return periodMs; } private: + friend class InternalTimerThread; + int countdownMs, periodMs; + Timer* previous; + Timer* next; - PropertiesFile* userProps; - PropertiesFile* commonProps; - - String appName, fileSuffix, folderName; - int msBeforeSaving, options; - int commonSettingsAreReadOnly; - - ApplicationProperties (const ApplicationProperties&); - const ApplicationProperties& operator= (const ApplicationProperties&); - - void openFiles() throw(); + const Timer& operator= (const Timer&); }; -#endif // __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ -/********* End of inlined file: juce_ApplicationProperties.h *********/ +#endif // __JUCE_TIMER_JUCEHEADER__ +/********* End of inlined file: juce_Timer.h *********/ -#endif -#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ +/** + Classes can implement this interface and register themselves with the Desktop class + to receive callbacks when the currently focused component changes. -/********* Start of inlined file: juce_MidiBuffer.h *********/ -#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ -#define __JUCE_MIDIBUFFER_JUCEHEADER__ + @see Desktop::addFocusChangeListener, Desktop::removeFocusChangeListener +*/ +class JUCE_API FocusChangeListener +{ +public: + /** Destructor. */ + virtual ~FocusChangeListener() {} -/********* Start of inlined file: juce_MidiMessage.h *********/ -#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ -#define __JUCE_MIDIMESSAGE_JUCEHEADER__ + /** Callback to indicate that the currently focused component has changed. */ + virtual void globalFocusChanged (Component* focusedComponent) = 0; +}; /** - Encapsulates a MIDI message. + Describes and controls aspects of the computer's desktop. - @see MidiMessageSequence, MidiOutput, MidiInput */ -class JUCE_API MidiMessage +class JUCE_API Desktop : private DeletedAtShutdown, + private Timer, + private AsyncUpdater { public: - /** Creates a 3-byte short midi message. - - @param byte1 message byte 1 - @param byte2 message byte 2 - @param byte3 message byte 3 - @param timeStamp the time to give the midi message - this value doesn't - use any particular units, so will be application-specific + /** There's only one dektop object, and this method will return it. */ - MidiMessage (const int byte1, - const int byte2, - const int byte3, - const double timeStamp = 0) throw(); + static Desktop& JUCE_CALLTYPE getInstance() throw(); - /** Creates a 2-byte short midi message. + /** Returns a list of the positions of all the monitors available. - @param byte1 message byte 1 - @param byte2 message byte 2 - @param timeStamp the time to give the midi message - this value doesn't - use any particular units, so will be application-specific + The first rectangle in the list will be the main monitor area. + + If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, + or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ - MidiMessage (const int byte1, - const int byte2, - const double timeStamp = 0) throw(); + const RectangleList getAllMonitorDisplayAreas (const bool clippedToWorkArea = true) const throw(); - /** Creates a 1-byte short midi message. + /** Returns the position and size of the main monitor. - @param byte1 message byte 1 - @param timeStamp the time to give the midi message - this value doesn't - use any particular units, so will be application-specific + If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, + or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ - MidiMessage (const int byte1, - const double timeStamp = 0) throw(); - - /** Creates a midi message from a block of data. */ - MidiMessage (const uint8* const data, - const int dataSize, - const double timeStamp = 0) throw(); + const Rectangle getMainMonitorArea (const bool clippedToWorkArea = true) const throw(); - /** Reads the next midi message from some data. + /** Returns the position and size of the monitor which contains this co-ordinate. - This will read as many bytes from a data stream as it needs to make a - complete message, and will return the number of bytes it used. This lets - you read a sequence of midi messages from a file or stream. + If none of the monitors contains the point, this will just return the + main monitor. - @param data the data to read from - @param size the maximum number of bytes it's allowed to read - @param numBytesUsed returns the number of bytes that were actually needed - @param lastStatusByte in a sequence of midi messages, the initial byte - can be dropped from a message if it's the same as the - first byte of the previous message, so this lets you - supply the byte to use if the first byte of the message - has in fact been dropped. - @param timeStamp the time to give the midi message - this value doesn't - use any particular units, so will be application-specific + If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, + or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ - MidiMessage (const uint8* data, - int size, - int& numBytesUsed, - uint8 lastStatusByte, - double timeStamp = 0) throw(); - - /** Creates a copy of another midi message. */ - MidiMessage (const MidiMessage& other) throw(); + const Rectangle getMonitorAreaContaining (int x, int y, const bool clippedToWorkArea = true) const throw(); - /** Creates a copy of another midi message, with a different timestamp. */ - MidiMessage (const MidiMessage& other, - const double newTimeStamp) throw(); + /** Returns the mouse position. - /** Destructor. */ - ~MidiMessage() throw(); + The co-ordinates are relative to the top-left of the main monitor. + */ + static void getMousePosition (int& x, int& y) throw(); - /** Copies this message from another one. */ - const MidiMessage& operator= (const MidiMessage& other) throw(); + /** Makes the mouse pointer jump to a given location. - /** Returns a pointer to the raw midi data. + The co-ordinates are relative to the top-left of the main monitor. + */ + static void setMousePosition (int x, int y) throw(); - @see getRawDataSize + /** Returns the last position at which a mouse button was pressed. */ - uint8* getRawData() const throw() { return data; } + static void getLastMouseDownPosition (int& x, int& y) throw(); - /** Returns the number of bytes of data in the message. + /** Returns the number of times the mouse button has been clicked since the + app started. - @see getRawData + Each mouse-down event increments this number by 1. */ - int getRawDataSize() const throw() { return size; } - - /** Returns the timestamp associated with this message. + static int getMouseButtonClickCounter() throw(); - The exact meaning of this time and its units will vary, as messages are used in - a variety of different contexts. + /** This lets you prevent the screensaver from becoming active. - If you're getting the message from a midi file, this could be a time in seconds, or - a number of ticks - see MidiFile::convertTimestampTicksToSeconds(). + Handy if you're running some sort of presentation app where having a screensaver + appear would be annoying. - If the message is being used in a MidiBuffer, it might indicate the number of - audio samples from the start of the buffer. + Pass false to disable the screensaver, and true to re-enable it. (Note that this + won't enable a screensaver unless the user has actually set one up). - If the message was created by a MidiInput, see MidiInputCallback::handleIncomingMidiMessage() - for details of the way that it initialises this value. + The disablement will only happen while the Juce application is the foreground + process - if another task is running in front of it, then the screensaver will + be unaffected. - @see setTimeStamp, addToTimeStamp + @see isScreenSaverEnabled */ - double getTimeStamp() const throw() { return timeStamp; } + static void setScreenSaverEnabled (const bool isEnabled) throw(); - /** Changes the message's associated timestamp. + /** Returns true if the screensaver has not been turned off. - The units for the timestamp will be application-specific - see the notes for getTimeStamp(). + This will return the last value passed into setScreenSaverEnabled(). Note that + it won't tell you whether the user is actually using a screen saver, just + whether this app is deliberately preventing one from running. - @see addToTimeStamp, getTimeStamp + @see setScreenSaverEnabled */ - void setTimeStamp (const double newTimestamp) throw() { timeStamp = newTimestamp; } + static bool isScreenSaverEnabled() throw(); - /** Adds a value to the message's timestamp. + /** Registers a MouseListener that will receive all mouse events that occur on + any component. - The units for the timestamp will be application-specific. + @see removeGlobalMouseListener */ - void addToTimeStamp (const double delta) throw() { timeStamp += delta; } + void addGlobalMouseListener (MouseListener* const listener) throw(); - /** Returns the midi channel associated with the message. + /** Unregisters a MouseListener that was added with the addGlobalMouseListener() + method. - @returns a value 1 to 16 if the message has a channel, or 0 if it hasn't (e.g. - if it's a sysex) - @see isForChannel, setChannel + @see addGlobalMouseListener */ - int getChannel() const throw(); - - /** Returns true if the message applies to the given midi channel. + void removeGlobalMouseListener (MouseListener* const listener) throw(); - @param channelNumber the channel number to look for, in the range 1 to 16 - @see getChannel, setChannel + /** Registers a MouseListener that will receive a callback whenever the focused + component changes. */ - bool isForChannel (const int channelNumber) const throw(); - - /** Changes the message's midi channel. - - This won't do anything for non-channel messages like sysexes. + void addFocusChangeListener (FocusChangeListener* const listener) throw(); - @param newChannelNumber the channel number to change it to, in the range 1 to 16 - */ - void setChannel (const int newChannelNumber) throw(); + /** Unregisters a listener that was added with addFocusChangeListener(). */ + void removeFocusChangeListener (FocusChangeListener* const listener) throw(); - /** Returns true if this is a system-exclusive message. - */ - bool isSysEx() const throw(); + /** Takes a component and makes it full-screen, removing the taskbar, dock, etc. - /** Returns a pointer to the sysex data inside the message. + The component must already be on the desktop for this method to work. It will + be resized to completely fill the screen and any extraneous taskbars, menu bars, + etc will be hidden. - If this event isn't a sysex event, it'll return 0. + To exit kiosk mode, just call setKioskModeComponent (0). When this is called, + the component that's currently being used will be resized back to the size + and position it was in before being put into this mode. - @see getSysExDataSize + If allowMenusAndBars is true, things like the menu and dock (on mac) are still + allowed to pop up when the mouse moves onto them. If this is false, it'll try + to hide as much on-screen paraphenalia as possible. */ - const uint8* getSysExData() const throw(); - - /** Returns the size of the sysex data. + void setKioskModeComponent (Component* componentToUse, + const bool allowMenusAndBars = true); - This value excludes the 0xf0 header byte and the 0xf7 at the end. + /** Returns the component that is currently being used in kiosk-mode. - @see getSysExData + This is the component that was last set by setKioskModeComponent(). If none + has been set, this returns 0. */ - int getSysExDataSize() const throw(); - - /** Returns true if this message is a 'key-down' event. + Component* getKioskModeComponent() const { return kioskModeComponent; } - @param returnTrueForVelocity0 if true, then if this event is a note-on with - velocity 0, it will still be considered to be a note-on and the - method will return true. If returnTrueForVelocity0 is false, then - if this is a note-on event with velocity 0, it'll be regarded as - a note-off, and the method will return false + /** Returns the number of components that are currently active as top-level + desktop windows. - @see isNoteOff, getNoteNumber, getVelocity, noteOn + @see getComponent, Component::addToDesktop */ - bool isNoteOn (const bool returnTrueForVelocity0 = false) const throw(); - - /** Creates a key-down message (using a floating-point velocity). + int getNumComponents() const throw(); - @param channel the midi channel, in the range 1 to 16 - @param noteNumber the key number, 0 to 127 - @param velocity in the range 0 to 1.0 - @see isNoteOn - */ - static const MidiMessage noteOn (const int channel, - const int noteNumber, - const float velocity) throw(); + /** Returns one of the top-level desktop window components. - /** Creates a key-down message (using an integer velocity). + The index is from 0 to getNumComponents() - 1. This could return 0 if the + index is out-of-range. - @param channel the midi channel, in the range 1 to 16 - @param noteNumber the key number, 0 to 127 - @param velocity in the range 0 to 127 - @see isNoteOn + @see getNumComponents, Component::addToDesktop */ - static const MidiMessage noteOn (const int channel, - const int noteNumber, - const uint8 velocity) throw(); + Component* getComponent (const int index) const throw(); - /** Returns true if this message is a 'key-up' event. + /** Finds the component at a given screen location. - If returnTrueForNoteOnVelocity0 is true, then his will also return true - for a note-on event with a velocity of 0. + This will drill down into top-level windows to find the child component at + the given position. - @see isNoteOn, getNoteNumber, getVelocity, noteOff + Returns 0 if the co-ordinates are inside a non-Juce window. */ - bool isNoteOff (const bool returnTrueForNoteOnVelocity0 = true) const throw(); - - /** Creates a key-up message. + Component* findComponentAt (const int screenX, + const int screenY) const; - @param channel the midi channel, in the range 1 to 16 - @param noteNumber the key number, 0 to 127 - @see isNoteOff - */ - static const MidiMessage noteOff (const int channel, - const int noteNumber) throw(); + juce_UseDebuggingNewOperator - /** Returns true if this message is a 'key-down' or 'key-up' event. + /** Tells this object to refresh its idea of what the screen resolution is. - @see isNoteOn, isNoteOff + (Called internally by the native code). */ - bool isNoteOnOrOff() const throw(); + void refreshMonitorSizes() throw(); - /** Returns the midi note number for note-on and note-off messages. + /** True if the OS supports semitransparent windows */ + static bool canUseSemiTransparentWindows() throw(); - If the message isn't a note-on or off, the value returned will be - meaningless. +private: - @see isNoteOff, getMidiNoteName, getMidiNoteInHertz, setNoteNumber - */ - int getNoteNumber() const throw(); + friend class Component; + friend class ComponentPeer; + SortedSet mouseListeners, focusListeners; + VoidArray desktopComponents; - /** Changes the midi note number of a note-on or note-off message. + friend class DeletedAtShutdown; + friend class TopLevelWindowManager; + Desktop() throw(); + ~Desktop() throw(); - If the message isn't a note on or off, this will do nothing. - */ - void setNoteNumber (const int newNoteNumber) throw(); + Array monitorCoordsClipped, monitorCoordsUnclipped; + int lastMouseX, lastMouseY; - /** Returns the velocity of a note-on or note-off message. + Component* kioskModeComponent; + Rectangle kioskComponentOriginalBounds; - The value returned will be in the range 0 to 127. + void timerCallback(); + void sendMouseMove(); + void resetTimer() throw(); - If the message isn't a note-on or off event, it will return 0. + int getNumDisplayMonitors() const throw(); + const Rectangle getDisplayMonitorCoordinates (const int index, const bool clippedToWorkArea) const throw(); - @see getFloatVelocity - */ - uint8 getVelocity() const throw(); + void addDesktopComponent (Component* const c) throw(); + void removeDesktopComponent (Component* const c) throw(); + void componentBroughtToFront (Component* const c) throw(); - /** Returns the velocity of a note-on or note-off message. + void triggerFocusCallback() throw(); + void handleAsyncUpdate(); - The value returned will be in the range 0 to 1.0 + Desktop (const Desktop&); + const Desktop& operator= (const Desktop&); +}; - If the message isn't a note-on or off event, it will return 0. +#endif // __JUCE_DESKTOP_JUCEHEADER__ +/********* End of inlined file: juce_Desktop.h *********/ - @see getVelocity, setVelocity - */ - float getFloatVelocity() const throw(); +class KeyPressMappingSet; +class ApplicationCommandManagerListener; - /** Changes the velocity of a note-on or note-off message. +/** + One of these objects holds a list of all the commands your app can perform, + and despatches these commands when needed. - If the message isn't a note on or off, this will do nothing. + Application commands are a good way to trigger actions in your app, e.g. "Quit", + "Copy", "Paste", etc. Menus, buttons and keypresses can all be given commands + to invoke automatically, which means you don't have to handle the result of a menu + or button click manually. Commands are despatched to ApplicationCommandTarget objects + which can choose which events they want to handle. - @param newVelocity the new velocity, in the range 0 to 1.0 - @see getFloatVelocity, multiplyVelocity - */ - void setVelocity (const float newVelocity) throw(); + This architecture also allows for nested ApplicationCommandTargets, so that for example + you could have two different objects, one inside the other, both of which can respond to + a "delete" command. Depending on which one has focus, the command will be sent to the + appropriate place, regardless of whether it was triggered by a menu, keypress or some other + method. - /** Multiplies the velocity of a note-on or note-off message by a given amount. + To set up your app to use commands, you'll need to do the following: - If the message isn't a note on or off, this will do nothing. + - Create a global ApplicationCommandManager to hold the list of all possible + commands. (This will also manage a set of key-mappings for them). - @param scaleFactor the value by which to multiply the velocity - @see setVelocity - */ - void multiplyVelocity (const float scaleFactor) throw(); + - Make some of your UI components (or other objects) inherit from ApplicationCommandTarget. + This allows the object to provide a list of commands that it can perform, and + to handle them. - /** Returns true if the message is a program (patch) change message. + - Register each type of command using ApplicationCommandManager::registerAllCommandsForTarget(), + or ApplicationCommandManager::registerCommand(). - @see getProgramChangeNumber, getGMInstrumentName - */ - bool isProgramChange() const throw(); + - If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings() + method to access the key-mapper object, which you will need to register as a key-listener + in whatever top-level component you're using. See the KeyPressMappingSet class for more help + about setting this up. - /** Returns the new program number of a program change message. + - Use methods such as PopupMenu::addCommandItem() or Button::setCommandToTrigger() to + cause these commands to be invoked automatically. - If the message isn't a program change, the value returned will be - nonsense. + - Commands can be invoked directly by your code using ApplicationCommandManager::invokeDirectly(). - @see isProgramChange, getGMInstrumentName - */ - int getProgramChangeNumber() const throw(); + When a command is invoked, the ApplicationCommandManager will try to choose the best + ApplicationCommandTarget to receive the specified command. To do this it will use the + current keyboard focus to see which component might be interested, and will search the + component hierarchy for those that also implement the ApplicationCommandTarget interface. + If an ApplicationCommandTarget isn't interested in the command that is being invoked, then + the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget() + method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns 0. At this + point if the command still hasn't been performed, it will be passed to the current + JUCEApplication object (which is itself an ApplicationCommandTarget). - /** Creates a program-change message. + To exert some custom control over which ApplicationCommandTarget is chosen to invoke a command, + you can override the ApplicationCommandManager::getFirstCommandTarget() method and choose + the object yourself. - @param channel the midi channel, in the range 1 to 16 - @param programNumber the midi program number, 0 to 127 - @see isProgramChange, getGMInstrumentName - */ - static const MidiMessage programChange (const int channel, - const int programNumber) throw(); + @see ApplicationCommandTarget, ApplicationCommandInfo +*/ +class JUCE_API ApplicationCommandManager : private AsyncUpdater, + private FocusChangeListener +{ +public: - /** Returns true if the message is a pitch-wheel move. + /** Creates an ApplicationCommandManager. - @see getPitchWheelValue, pitchWheel + Once created, you'll need to register all your app's commands with it, using + ApplicationCommandManager::registerAllCommandsForTarget() or + ApplicationCommandManager::registerCommand(). */ - bool isPitchWheel() const throw(); - - /** Returns the pitch wheel position from a pitch-wheel move message. + ApplicationCommandManager(); - The value returned is a 14-bit number from 0 to 0x3fff, indicating the wheel position. - If called for messages which aren't pitch wheel events, the number returned will be - nonsense. + /** Destructor. - @see isPitchWheel + Make sure that you don't delete this if pointers to it are still being used by + objects such as PopupMenus or Buttons. */ - int getPitchWheelValue() const throw(); + virtual ~ApplicationCommandManager(); - /** Creates a pitch-wheel move message. + /** Clears the current list of all commands. - @param channel the midi channel, in the range 1 to 16 - @param position the wheel position, in the range 0 to 16383 - @see isPitchWheel + Note that this will also clear the contents of the KeyPressMappingSet. */ - static const MidiMessage pitchWheel (const int channel, - const int position) throw(); - - /** Returns true if the message is an aftertouch event. + void clearCommands(); - For aftertouch events, use the getNoteNumber() method to find out the key - that it applies to, and getAftertouchValue() to find out the amount. Use - getChannel() to find out the channel. + /** Adds a command to the list of registered commands. - @see getAftertouchValue, getNoteNumber + @see registerAllCommandsForTarget */ - bool isAftertouch() const throw(); + void registerCommand (const ApplicationCommandInfo& newCommand); - /** Returns the amount of aftertouch from an aftertouch messages. + /** Adds all the commands that this target publishes to the manager's list. - The value returned is in the range 0 to 127, and will be nonsense for messages - other than aftertouch messages. + This will use ApplicationCommandTarget::getAllCommands() and ApplicationCommandTarget::getCommandInfo() + to get details about all the commands that this target can do, and will call + registerCommand() to add each one to the manger's list. - @see isAftertouch + @see registerCommand */ - int getAfterTouchValue() const throw(); + void registerAllCommandsForTarget (ApplicationCommandTarget* target); - /** Creates an aftertouch message. + /** Removes the command with a specified ID. - @param channel the midi channel, in the range 1 to 16 - @param noteNumber the key number, 0 to 127 - @param aftertouchAmount the amount of aftertouch, 0 to 127 - @see isAftertouch + Note that this will also remove any key mappings that are mapped to the command. */ - static const MidiMessage aftertouchChange (const int channel, - const int noteNumber, - const int aftertouchAmount) throw(); + void removeCommand (const CommandID commandID); - /** Returns true if the message is a channel-pressure change event. + /** This should be called to tell the manager that one of its registered commands may have changed + its active status. - This is like aftertouch, but common to the whole channel rather than a specific - note. Use getChannelPressureValue() to find out the pressure, and getChannel() - to find out the channel. + Because the command manager only finds out whether a command is active or inactive by querying + the current ApplicationCommandTarget, this is used to tell it that things may have changed. It + allows things like buttons to update their enablement, etc. - @see channelPressureChange + This method will cause an asynchronous call to ApplicationCommandManagerListener::applicationCommandListChanged() + for any registered listeners. */ - bool isChannelPressure() const throw(); + void commandStatusChanged(); - /** Returns the pressure from a channel pressure change message. + /** Returns the number of commands that have been registered. - @returns the pressure, in the range 0 to 127 - @see isChannelPressure, channelPressureChange + @see registerCommand */ - int getChannelPressureValue() const throw(); + int getNumCommands() const throw() { return commands.size(); } - /** Creates a channel-pressure change event. + /** Returns the details about one of the registered commands. - @param channel the midi channel: 1 to 16 - @param pressure the pressure, 0 to 127 - @see isChannelPressure + The index is between 0 and (getNumCommands() - 1). */ - static const MidiMessage channelPressureChange (const int channel, - const int pressure) throw(); + const ApplicationCommandInfo* getCommandForIndex (const int index) const throw() { return commands [index]; } - /** Returns true if this is a midi controller message. + /** Returns the details about a given command ID. - @see getControllerNumber, getControllerValue, controllerEvent + This will search the list of registered commands for one with the given command + ID number, and return its associated info. If no matching command is found, this + will return 0. */ - bool isController() const throw(); + const ApplicationCommandInfo* getCommandForID (const CommandID commandID) const throw(); - /** Returns the controller number of a controller message. + /** Returns the name field for a command. - The name of the controller can be looked up using the getControllerName() method. + An empty string is returned if no command with this ID has been registered. + @see getDescriptionOfCommand + */ + const String getNameOfCommand (const CommandID commandID) const throw(); - Note that the value returned is invalid for messages that aren't controller changes. + /** Returns the description field for a command. - @see isController, getControllerName, getControllerValue - */ - int getControllerNumber() const throw(); + An empty string is returned if no command with this ID has been registered. If the + command has no description, this will return its short name field instead. - /** Returns the controller value from a controller message. + @see getNameOfCommand + */ + const String getDescriptionOfCommand (const CommandID commandID) const throw(); - A value 0 to 127 is returned to indicate the new controller position. + /** Returns the list of categories. - Note that the value returned is invalid for messages that aren't controller changes. + This will go through all registered commands, and return a list of all the distict + categoryName values from their ApplicationCommandInfo structure. - @see isController, getControllerNumber + @see getCommandsInCategory() */ - int getControllerValue() const throw(); + const StringArray getCommandCategories() const throw(); - /** Creates a controller message. + /** Returns a list of all the command UIDs in a particular category. - @param channel the midi channel, in the range 1 to 16 - @param controllerType the type of controller - @param value the controller value - @see isController + @see getCommandCategories() */ - static const MidiMessage controllerEvent (const int channel, - const int controllerType, - const int value) throw(); + const Array getCommandsInCategory (const String& categoryName) const throw(); - /** Checks whether this message is an all-notes-off message. + /** Returns the manager's internal set of key mappings. - @see allNotesOff + This object can be used to edit the keypresses. To actually link this object up + to invoke commands when a key is pressed, see the comments for the KeyPressMappingSet + class. + + @see KeyPressMappingSet */ - bool isAllNotesOff() const throw(); + KeyPressMappingSet* getKeyMappings() const throw() { return keyMappings; } - /** Checks whether this message is an all-sound-off message. + /** Invokes the given command directly, sending it to the default target. - @see allSoundOff + This is just an easy way to call invoke() without having to fill out the InvocationInfo + structure. */ - bool isAllSoundOff() const throw(); + bool invokeDirectly (const CommandID commandID, + const bool asynchronously); - /** Creates an all-notes-off message. + /** Sends a command to the default target. - @param channel the midi channel, in the range 1 to 16 - @see isAllNotesOff - */ - static const MidiMessage allNotesOff (const int channel) throw(); + This will choose a target using getFirstCommandTarget(), and send the specified command + to it using the ApplicationCommandTarget::invoke() method. This means that if the + first target can't handle the command, it will be passed on to targets further down the + chain (see ApplicationCommandTarget::invoke() for more info). - /** Creates an all-sound-off message. + @param invocationInfo this must be correctly filled-in, describing the context for + the invocation. + @param asynchronously if false, the command will be performed before this method returns. + If true, a message will be posted so that the command will be performed + later on the message thread, and this method will return immediately. - @param channel the midi channel, in the range 1 to 16 - @see isAllSoundOff + @see ApplicationCommandTarget::invoke */ - static const MidiMessage allSoundOff (const int channel) throw(); + bool invoke (const ApplicationCommandTarget::InvocationInfo& invocationInfo, + const bool asynchronously); - /** Creates an all-controllers-off message. + /** Chooses the ApplicationCommandTarget to which a command should be sent. - @param channel the midi channel, in the range 1 to 16 - */ - static const MidiMessage allControllersOff (const int channel) throw(); + Whenever the manager needs to know which target a command should be sent to, it calls + this method to determine the first one to try. - /** Returns true if this event is a meta-event. + By default, this method will return the target that was set by calling setFirstCommandTarget(). + If no target is set, it will return the result of findDefaultComponentTarget(). - Meta-events are things like tempo changes, track names, etc. + If you need to make sure all commands go via your own custom target, then you can + either use setFirstCommandTarget() to specify a single target, or override this method + if you need more complex logic to choose one. - @see getMetaEventType, isTrackMetaEvent, isEndOfTrackMetaEvent, - isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, - isKeySignatureMetaEvent, isMidiChannelMetaEvent + It may return 0 if no targets are available. + + @see getTargetForCommand, invoke, invokeDirectly */ - bool isMetaEvent() const throw(); + virtual ApplicationCommandTarget* getFirstCommandTarget (const CommandID commandID); - /** Returns a meta-event's type number. + /** Sets a target to be returned by getFirstCommandTarget(). - If the message isn't a meta-event, this will return -1. + If this is set to 0, then getFirstCommandTarget() will by default return the + result of findDefaultComponentTarget(). - @see isMetaEvent, isTrackMetaEvent, isEndOfTrackMetaEvent, - isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, - isKeySignatureMetaEvent, isMidiChannelMetaEvent + If you use this to set a target, make sure you call setFirstCommandTarget (0) before + deleting the target object. */ - int getMetaEventType() const throw(); + void setFirstCommandTarget (ApplicationCommandTarget* const newTarget) throw(); - /** Returns a pointer to the data in a meta-event. + /** Tries to find the best target to use to perform a given command. - @see isMetaEvent, getMetaEventLength - */ - const uint8* getMetaEventData() const throw(); + This will call getFirstCommandTarget() to find the preferred target, and will + check whether that target can handle the given command. If it can't, then it'll use + ApplicationCommandTarget::getNextCommandTarget() to find the next one to try, and + so on until no more are available. - /** Returns the length of the data for a meta-event. + If no targets are found that can perform the command, this method will return 0. - @see isMetaEvent, getMetaEventData + If a target is found, then it will get the target to fill-in the upToDateInfo + structure with the latest info about that command, so that the caller can see + whether the command is disabled, ticked, etc. */ - int getMetaEventLength() const throw(); - - /** Returns true if this is a 'track' meta-event. */ - bool isTrackMetaEvent() const throw(); + ApplicationCommandTarget* getTargetForCommand (const CommandID commandID, + ApplicationCommandInfo& upToDateInfo); - /** Returns true if this is an 'end-of-track' meta-event. */ - bool isEndOfTrackMetaEvent() const throw(); + /** Registers a listener that will be called when various events occur. */ + void addListener (ApplicationCommandManagerListener* const listener) throw(); - /** Creates an end-of-track meta-event. + /** Deregisters a previously-added listener. */ + void removeListener (ApplicationCommandManagerListener* const listener) throw(); - @see isEndOfTrackMetaEvent - */ - static const MidiMessage endOfTrack() throw(); + /** Looks for a suitable command target based on which Components have the keyboard focus. - /** Returns true if this is an 'track name' meta-event. + This is used by the default implementation of ApplicationCommandTarget::getFirstCommandTarget(), + but is exposed here in case it's useful. - You can use the getTextFromTextMetaEvent() method to get the track's name. + It tries to pick the best ApplicationCommandTarget by looking at focused components, top level + windows, etc., and using the findTargetForComponent() method. */ - bool isTrackNameEvent() const throw(); + static ApplicationCommandTarget* findDefaultComponentTarget(); - /** Returns true if this is a 'text' meta-event. + /** Examines this component and all its parents in turn, looking for the first one + which is a ApplicationCommandTarget. - @see getTextFromTextMetaEvent + Returns the first ApplicationCommandTarget that it finds, or 0 if none of them implement + that class. */ - bool isTextMetaEvent() const throw(); + static ApplicationCommandTarget* findTargetForComponent (Component* component); - /** Returns the text from a text meta-event. + juce_UseDebuggingNewOperator - @see isTextMetaEvent - */ - const String getTextFromTextMetaEvent() const throw(); +private: - /** Returns true if this is a 'tempo' meta-event. + OwnedArray commands; + SortedSet listeners; + KeyPressMappingSet* keyMappings; + ApplicationCommandTarget* firstTarget; - @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote - */ - bool isTempoMetaEvent() const throw(); + void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) const; + void handleAsyncUpdate(); + void globalFocusChanged (Component*); - /** Returns the tick length from a tempo meta-event. + // xxx this is just here to cause a compile error in old code that hasn't been changed to use the new + // version of this method. + virtual short getFirstCommandTarget() { return 0; } +}; - @param timeFormat the 16-bit time format value from the midi file's header. - @returns the tick length (in seconds). - @see isTempoMetaEvent - */ - double getTempoMetaEventTickLength (const short timeFormat) const throw(); +/** + A listener that receives callbacks from an ApplicationCommandManager when + commands are invoked or the command list is changed. - /** Calculates the seconds-per-quarter-note from a tempo meta-event. + @see ApplicationCommandManager::addListener, ApplicationCommandManager::removeListener - @see isTempoMetaEvent, getTempoMetaEventTickLength - */ - double getTempoSecondsPerQuarterNote() const throw(); +*/ +class JUCE_API ApplicationCommandManagerListener +{ +public: - /** Creates a tempo meta-event. + /** Destructor. */ + virtual ~ApplicationCommandManagerListener() {} - @see isTempoMetaEvent - */ - static const MidiMessage tempoMetaEvent (const int microsecondsPerQuarterNote) throw(); + /** Called when an app command is about to be invoked. */ + virtual void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) = 0; - /** Returns true if this is a 'time-signature' meta-event. + /** Called when commands are registered or deregistered from the + command manager, or when commands are made active or inactive. - @see getTimeSignatureInfo + Note that if you're using this to watch for changes to whether a command is disabled, + you'll need to make sure that ApplicationCommandManager::commandStatusChanged() is called + whenever the status of your command might have changed. */ - bool isTimeSignatureMetaEvent() const throw(); + virtual void applicationCommandListChanged() = 0; +}; - /** Returns the time-signature values from a time-signature meta-event. +#endif // __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_ApplicationCommandManager.h *********/ - @see isTimeSignatureMetaEvent - */ - void getTimeSignatureInfo (int& numerator, - int& denominator) const throw(); +#endif +#ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ - /** Creates a time-signature meta-event. +#endif +#ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ - @see isTimeSignatureMetaEvent - */ - static const MidiMessage timeSignatureMetaEvent (const int numerator, - const int denominator) throw(); +/********* Start of inlined file: juce_ApplicationProperties.h *********/ +#ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ +#define __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ - /** Returns true if this is a 'key-signature' meta-event. +/********* Start of inlined file: juce_PropertiesFile.h *********/ +#ifndef __JUCE_PROPERTIESFILE_JUCEHEADER__ +#define __JUCE_PROPERTIESFILE_JUCEHEADER__ - @see getKeySignatureNumberOfSharpsOrFlats - */ - bool isKeySignatureMetaEvent() const throw(); +/** Wrapper on a file that stores a list of key/value data pairs. - /** Returns the key from a key-signature meta-event. + Useful for storing application settings, etc. See the PropertySet class for + the interfaces that read and write values. - @see isKeySignatureMetaEvent - */ - int getKeySignatureNumberOfSharpsOrFlats() const throw(); + Not designed for very large amounts of data, as it keeps all the values in + memory and writes them out to disk lazily when they are changed. - /** Returns true if this is a 'channel' meta-event. + Because this class derives from ChangeBroadcaster, ChangeListeners can be registered + with it, and these will be signalled when a value changes. - A channel meta-event specifies the midi channel that should be used - for subsequent meta-events. + @see PropertySet +*/ +class JUCE_API PropertiesFile : public PropertySet, + public ChangeBroadcaster, + private Timer +{ +public: - @see getMidiChannelMetaEventChannel - */ - bool isMidiChannelMetaEvent() const throw(); + enum FileFormatOptions + { + ignoreCaseOfKeyNames = 1, + storeAsBinary = 2, + storeAsCompressedBinary = 4, + storeAsXML = 8 + }; - /** Returns the channel number from a channel meta-event. + /** + Creates a PropertiesFile object. - @returns the channel, in the range 1 to 16. - @see isMidiChannelMetaEvent + @param file the file to use + @param millisecondsBeforeSaving if this is zero or greater, then after a value + is changed, the object will wait for this amount + of time and then save the file. If zero, the file + will be written to disk immediately on being changed + (which might be slow, as it'll re-write synchronously + each time a value-change method is called). If it is + less than zero, the file won't be saved until + save() or saveIfNeeded() are explicitly called. + @param options a combination of the flags in the FileFormatOptions + enum, which specify the type of file to save, and other + options. */ - int getMidiChannelMetaEventChannel() const throw(); + PropertiesFile (const File& file, + const int millisecondsBeforeSaving, + const int options) throw(); - /** Creates a midi channel meta-event. + /** Destructor. - @param channel the midi channel, in the range 1 to 16 - @see isMidiChannelMetaEvent + When deleted, the file will first call saveIfNeeded() to flush any changes to disk. */ - static const MidiMessage midiChannelMetaEvent (const int channel) throw(); + ~PropertiesFile(); - /** Returns true if this is an active-sense message. */ - bool isActiveSense() const throw(); + /** This will flush all the values to disk if they've changed since the last + time they were saved. - /** Returns true if this is a midi start event. + Returns false if it fails to write to the file for some reason (maybe because + it's read-only or the directory doesn't exist or something). - @see midiStart + @see save */ - bool isMidiStart() const throw(); + bool saveIfNeeded(); - /** Creates a midi start event. */ - static const MidiMessage midiStart() throw(); + /** This will force a write-to-disk of the current values, regardless of whether + anything has changed since the last save. - /** Returns true if this is a midi continue event. + Returns false if it fails to write to the file for some reason (maybe because + it's read-only or the directory doesn't exist or something). - @see midiContinue + @see saveIfNeeded */ - bool isMidiContinue() const throw(); - - /** Creates a midi continue event. */ - static const MidiMessage midiContinue() throw(); - - /** Returns true if this is a midi stop event. + bool save(); - @see midiStop + /** Returns true if the properties have been altered since the last time they were + saved. */ - bool isMidiStop() const throw(); - - /** Creates a midi stop event. */ - static const MidiMessage midiStop() throw(); - - /** Returns true if this is a midi clock event. + bool needsToBeSaved() const throw(); - @see midiClock, songPositionPointer - */ - bool isMidiClock() const throw(); + /** Returns the file that's being used. */ + const File getFile() const throw(); - /** Creates a midi clock event. */ - static const MidiMessage midiClock() throw(); + /** Handy utility to create a properties file in whatever the standard OS-specific + location is for these things. - /** Returns true if this is a song-position-pointer message. + This uses getDefaultAppSettingsFile() to decide what file to create, then + creates a PropertiesFile object with the specified properties. See + getDefaultAppSettingsFile() and the class's constructor for descriptions of + what the parameters do. - @see getSongPositionPointerMidiBeat, songPositionPointer + @see getDefaultAppSettingsFile */ - bool isSongPositionPointer() const throw(); - - /** Returns the midi beat-number of a song-position-pointer message. + static PropertiesFile* createDefaultAppPropertiesFile (const String& applicationName, + const String& fileNameSuffix, + const String& folderName, + const bool commonToAllUsers, + const int millisecondsBeforeSaving, + const int propertiesFileOptions); - @see isSongPositionPointer, songPositionPointer - */ - int getSongPositionPointerMidiBeat() const throw(); + /** Handy utility to choose a file in the standard OS-dependent location for application + settings files. - /** Creates a song-position-pointer message. + So on a Mac, this will return a file called: + ~/Library/Preferences/[folderName]/[applicationName].[fileNameSuffix] - The position is a number of midi beats from the start of the song, where 1 midi - beat is 6 midi clocks, and there are 24 midi clocks in a quarter-note. So there - are 4 midi beats in a quarter-note. + On Windows it'll return something like: + C:\\Documents and Settings\\username\\Application Data\\[folderName]\\[applicationName].[fileNameSuffix] - @see isSongPositionPointer, getSongPositionPointerMidiBeat - */ - static const MidiMessage songPositionPointer (const int positionInMidiBeats) throw(); + On Linux it'll return + ~/.[folderName]/[applicationName].[fileNameSuffix] - /** Returns true if this is a quarter-frame midi timecode message. + If you pass an empty string as the folder name, it'll use the app name for this (or + omit the folder name on the Mac). - @see quarterFrame, getQuarterFrameSequenceNumber, getQuarterFrameValue + If commonToAllUsers is true, then this will return the same file for all users of the + computer, regardless of the current user. If it is false, the file will be specific to + only the current user. Use this to choose whether you're saving settings that are common + or user-specific. */ - bool isQuarterFrame() const throw(); + static const File getDefaultAppSettingsFile (const String& applicationName, + const String& fileNameSuffix, + const String& folderName, + const bool commonToAllUsers); - /** Returns the sequence number of a quarter-frame midi timecode message. + juce_UseDebuggingNewOperator - This will be a value between 0 and 7. +protected: + virtual void propertyChanged(); - @see isQuarterFrame, getQuarterFrameValue, quarterFrame - */ - int getQuarterFrameSequenceNumber() const throw(); +private: - /** Returns the value from a quarter-frame message. + File file; + int timerInterval; + const int options; + bool needsWriting; - This will be the lower nybble of the message's data-byte, a value - between 0 and 15 - */ - int getQuarterFrameValue() const throw(); + void timerCallback(); - /** Creates a quarter-frame MTC message. + PropertiesFile (const PropertiesFile&); + const PropertiesFile& operator= (const PropertiesFile&); +}; - @param sequenceNumber a value 0 to 7 for the upper nybble of the message's data byte - @param value a value 0 to 15 for the lower nybble of the message's data byte - */ - static const MidiMessage quarterFrame (const int sequenceNumber, - const int value) throw(); +#endif // __JUCE_PROPERTIESFILE_JUCEHEADER__ +/********* End of inlined file: juce_PropertiesFile.h *********/ - /** SMPTE timecode types. +/** + Manages a collection of properties. - Used by the getFullFrameParameters() and fullFrame() methods. - */ - enum SmpteTimecodeType - { - fps24 = 0, - fps25 = 1, - fps30drop = 2, - fps30 = 3 - }; + This is a slightly higher-level wrapper for PropertiesFile, which can be used + as a singleton. - /** Returns true if this is a full-frame midi timecode message. - */ - bool isFullFrame() const throw(); + It holds two different PropertiesFile objects internally, one for user-specific + settings (stored in your user directory), and one for settings that are common to + all users (stored in a folder accessible to all users). - /** Extracts the timecode information from a full-frame midi timecode message. + The class manages the creation of these files on-demand, allowing access via the + getUserSettings() and getCommonSettings() methods. It also has a few handy + methods like testWriteAccess() to check that the files can be saved. - You should only call this on messages where you've used isFullFrame() to - check that they're the right kind. - */ - void getFullFrameParameters (int& hours, - int& minutes, - int& seconds, - int& frames, - SmpteTimecodeType& timecodeType) const throw(); + If you're using one of these as a singleton, then your app's start-up code should + first of all call setStorageParameters() to tell it the parameters to use to create + the properties files. - /** Creates a full-frame MTC message. - */ - static const MidiMessage fullFrame (const int hours, - const int minutes, - const int seconds, - const int frames, - SmpteTimecodeType timecodeType); + @see PropertiesFile +*/ +class JUCE_API ApplicationProperties : public DeletedAtShutdown +{ +public: - /** Types of MMC command. + /** + Creates an ApplicationProperties object. - @see isMidiMachineControlMessage, getMidiMachineControlCommand, midiMachineControlCommand + Before using it, you must call setStorageParameters() to give it the info + it needs to create the property files. */ - enum MidiMachineControlCommand - { - mmc_stop = 1, - mmc_play = 2, - mmc_deferredplay = 3, - mmc_fastforward = 4, - mmc_rewind = 5, - mmc_recordStart = 6, - mmc_recordStop = 7, - mmc_pause = 9 - }; - - /** Checks whether this is an MMC message. + ApplicationProperties() throw(); - If it is, you can use the getMidiMachineControlCommand() to find out its type. + /** Destructor. */ - bool isMidiMachineControlMessage() const throw(); + ~ApplicationProperties(); - /** For an MMC message, this returns its type. + juce_DeclareSingleton (ApplicationProperties, false) - Make sure it's actually an MMC message with isMidiMachineControlMessage() before - calling this method. - */ - MidiMachineControlCommand getMidiMachineControlCommand() const throw(); + /** Gives the object the information it needs to create the appropriate properties files. - /** Creates an MMC message. + See the comments for PropertiesFile::createDefaultAppPropertiesFile() for more + info about how these parameters are used. */ - static const MidiMessage midiMachineControlCommand (MidiMachineControlCommand command); + void setStorageParameters (const String& applicationName, + const String& fileNameSuffix, + const String& folderName, + const int millisecondsBeforeSaving, + const int propertiesFileOptions) throw(); - /** Checks whether this is an MMC "goto" message. + /** Tests whether the files can be successfully written to, and can show + an error message if not. - If it is, the parameters passed-in are set to the time that the message contains. + Returns true if none of the tests fail. - @see midiMachineControlGoto + @param testUserSettings if true, the user settings file will be tested + @param testCommonSettings if true, the common settings file will be tested + @param showWarningDialogOnFailure if true, the method will show a helpful error + message box if either of the tests fail */ - bool isMidiMachineControlGoto (int& hours, - int& minutes, - int& seconds, - int& frames) const throw(); - - /** Creates an MMC "goto" message. + bool testWriteAccess (const bool testUserSettings, + const bool testCommonSettings, + const bool showWarningDialogOnFailure); - This messages tells the device to go to a specific frame. + /** Returns the user settings file. - @see isMidiMachineControlGoto - */ - static const MidiMessage midiMachineControlGoto (int hours, - int minutes, - int seconds, - int frames); + The first time this is called, it will create and load the properties file. - /** Creates a master-volume change message. + Note that when you search the user PropertiesFile for a value that it doesn't contain, + the common settings are used as a second-chance place to look. This is done via the + PropertySet::setFallbackPropertySet() method - by default the common settings are set + to the fallback for the user settings. - @param volume the volume, 0 to 1.0 + @see getCommonSettings */ - static const MidiMessage masterVolume (const float volume) throw(); - - /** Creates a system-exclusive message. + PropertiesFile* getUserSettings() throw(); - The data passed in is wrapped with header and tail bytes of 0xf0 and 0xf7. - */ - static const MidiMessage createSysExMessage (const uint8* sysexData, - const int dataSize) throw(); + /** Returns the common settings file. - /** Reads a midi variable-length integer. + The first time this is called, it will create and load the properties file. - @param data the data to read the number from - @param numBytesUsed on return, this will be set to the number of bytes that were read + @param returnUserPropsIfReadOnly if this is true, and the common properties file is + read-only (e.g. because the user doesn't have permission to write + to shared files), then this will return the user settings instead, + (like getUserSettings() would do). This is handy if you'd like to + write a value to the common settings, but if that's no possible, + then you'd rather write to the user settings than none at all. + If returnUserPropsIfReadOnly is false, this method will always return + the common settings, even if any changes to them can't be saved. + @see getUserSettings */ - static int readVariableLengthVal (const uint8* data, - int& numBytesUsed) throw(); + PropertiesFile* getCommonSettings (const bool returnUserPropsIfReadOnly) throw(); - /** Based on the first byte of a short midi message, this uses a lookup table - to return the message length (either 1, 2, or 3 bytes). + /** Saves both files if they need to be saved. - The value passed in must be 0x80 or higher. + @see PropertiesFile::saveIfNeeded */ - static int getMessageLengthFromFirstByte (const uint8 firstByte) throw(); - - /** Returns the name of a midi note number. - - E.g "C", "D#", etc. + bool saveIfNeeded(); - @param noteNumber the midi note number, 0 to 127 - @param useSharps if true, sharpened notes are used, e.g. "C#", otherwise - they'll be flattened, e.g. "Db" - @param includeOctaveNumber if true, the octave number will be appended to the string, - e.g. "C#4" - @param octaveNumForMiddleC if an octave number is being appended, this indicates the - number that will be used for middle C's octave + /** Flushes and closes both files if they are open. - @see getMidiNoteInHertz + This flushes any pending changes to disk with PropertiesFile::saveIfNeeded() + and closes both files. They will then be re-opened the next time getUserSettings() + or getCommonSettings() is called. */ - static const String getMidiNoteName (int noteNumber, - bool useSharps, - bool includeOctaveNumber, - int octaveNumForMiddleC) throw(); - - /** Returns the frequency of a midi note number. + void closeFiles(); - @see getMidiNoteName - */ - static const double getMidiNoteInHertz (int noteNumber) throw(); + juce_UseDebuggingNewOperator - /** Returns the standard name of a GM instrument. +private: - @param midiInstrumentNumber the program number 0 to 127 - @see getProgramChangeNumber - */ - static const String getGMInstrumentName (int midiInstrumentNumber) throw(); + PropertiesFile* userProps; + PropertiesFile* commonProps; - /** Returns the name of a bank of GM instruments. + String appName, fileSuffix, folderName; + int msBeforeSaving, options; + int commonSettingsAreReadOnly; - @param midiBankNumber the bank, 0 to 15 - */ - static const String getGMInstrumentBankName (int midiBankNumber) throw(); + ApplicationProperties (const ApplicationProperties&); + const ApplicationProperties& operator= (const ApplicationProperties&); - /** Returns the standard name of a channel 10 percussion sound. + void openFiles() throw(); +}; - @param midiNoteNumber the key number, 35 to 81 - */ - static const String getRhythmInstrumentName (int midiNoteNumber) throw(); +#endif // __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ +/********* End of inlined file: juce_ApplicationProperties.h *********/ - /** Returns the name of a controller type number. +#endif +#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ - @see getControllerNumber - */ - static const String getControllerName (int controllerNumber) throw(); +/********* Start of inlined file: juce_AiffAudioFormat.h *********/ +#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ +#define __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ - juce_UseDebuggingNewOperator +/********* Start of inlined file: juce_AudioFormat.h *********/ +#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ +#define __JUCE_AUDIOFORMAT_JUCEHEADER__ -private: - double timeStamp; - uint8* data; - int message, size; -}; +/********* Start of inlined file: juce_AudioFormatReader.h *********/ +#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ +#define __JUCE_AUDIOFORMATREADER_JUCEHEADER__ -#endif // __JUCE_MIDIMESSAGE_JUCEHEADER__ -/********* End of inlined file: juce_MidiMessage.h *********/ +class AudioFormat; /** - Holds a sequence of time-stamped midi events. + Reads samples from an audio file stream. - Analogous to the AudioSampleBuffer, this holds a set of midi events with - integer time-stamps. The buffer is kept sorted in order of the time-stamps. + A subclass that reads a specific type of audio format will be created by + an AudioFormat object. - @see MidiMessage + @see AudioFormat, AudioFormatWriter */ -class JUCE_API MidiBuffer +class JUCE_API AudioFormatReader { -public: +protected: - /** Creates an empty MidiBuffer. */ - MidiBuffer() throw(); - - /** Creates a MidiBuffer containing a single midi message. */ - MidiBuffer (const MidiMessage& message) throw(); - - /** Creates a copy of another MidiBuffer. */ - MidiBuffer (const MidiBuffer& other) throw(); - - /** Makes a copy of another MidiBuffer. */ - const MidiBuffer& operator= (const MidiBuffer& other) throw(); - - /** Destructor */ - ~MidiBuffer() throw(); - - /** Removes all events from the buffer. */ - void clear() throw(); - - /** Removes all events between two times from the buffer. + /** Creates an AudioFormatReader object. - All events for which (start <= event position < start + numSamples) will - be removed. + @param sourceStream the stream to read from - this will be deleted + by this object when it is no longer needed. (Some + specialised readers might not use this parameter and + can leave it as 0). + @param formatName the description that will be returned by the getFormatName() + method */ - void clear (const int start, - const int numSamples) throw(); - - /** Returns true if the buffer is empty. + AudioFormatReader (InputStream* const sourceStream, + const String& formatName); - To actually retrieve the events, use a MidiBuffer::Iterator object - */ - bool isEmpty() const throw(); +public: + /** Destructor. */ + virtual ~AudioFormatReader(); - /** Counts the number of events in the buffer. + /** Returns a description of what type of format this is. - This is actually quite a slow operation, as it has to iterate through all - the events, so you might prefer to call isEmpty() if that's all you need - to know. + E.g. "AIFF" */ - int getNumEvents() const throw(); - - /** Adds an event to the buffer. - - The sample number will be used to determine the position of the event in - the buffer, which is always kept sorted. The MidiMessage's timestamp is - ignored. + const String getFormatName() const throw() { return formatName; } - If an event is added whose sample position is the same as one or more events - already in the buffer, the new event will be placed after the existing ones. + /** Reads samples from the stream. - To retrieve events, use a MidiBuffer::Iterator object + @param destSamples an array of buffers into which the sample data for each + channel will be written. + If the format is fixed-point, each channel will be written + as an array of 32-bit signed integers using the full + range -0x80000000 to 0x7fffffff, regardless of the source's + bit-depth. If it is a floating-point format, you should cast + the resulting array to a (float**) to get the values (in the + range -1.0 to 1.0 or beyond) + If the format is stereo, then destSamples[0] is the left channel + data, and destSamples[1] is the right channel. + The numDestChannels parameter indicates how many pointers this array + contains, but some of these pointers can be null if you don't want to + read data for some of the channels + @param numDestChannels the number of array elements in the destChannels array + @param startSampleInSource the position in the audio file or stream at which the samples + should be read, as a number of samples from the start of the + stream. It's ok for this to be beyond the start or end of the + available data - any samples that are out-of-range will be returned + as zeros. + @param numSamplesToRead the number of samples to read. If this is greater than the number + of samples that the file or stream contains. the result will be padded + with zeros + @param fillLeftoverChannelsWithCopies if true, this indicates that if there's no source data available + for some of the channels that you pass in, then they should be filled with + copies of valid source channels. + E.g. if you're reading a mono file and you pass 2 channels to this method, then + if fillLeftoverChannelsWithCopies is true, both destination channels will be filled + with the same data from the file's single channel. If fillLeftoverChannelsWithCopies + was false, then only the first channel would be filled with the file's contents, and + the second would be cleared. If there are many channels, e.g. you try to read 4 channels + from a stereo file, then the last 3 would all end up with copies of the same data. + @returns true if the operation succeeded, false if there was an error. Note + that reading sections of data beyond the extent of the stream isn't an + error - the reader should just return zeros for these regions + @see readMaxLevels */ - void addEvent (const MidiMessage& midiMessage, - const int sampleNumber) throw(); - - /** Adds an event to the buffer from raw midi data. - - The sample number will be used to determine the position of the event in - the buffer, which is always kept sorted. - - If an event is added whose sample position is the same as one or more events - already in the buffer, the new event will be placed after the existing ones. - - The event data will be inspected to calculate the number of bytes in length that - the midi event really takes up, so maxBytesOfMidiData may be longer than the data - that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes, - it'll actually only store 3 bytes. If the midi data is invalid, it might not - add an event at all. + bool read (int** destSamples, + int numDestChannels, + int64 startSampleInSource, + int numSamplesToRead, + const bool fillLeftoverChannelsWithCopies); - To retrieve events, use a MidiBuffer::Iterator object - */ - void addEvent (const uint8* const rawMidiData, - const int maxBytesOfMidiData, - const int sampleNumber) throw(); + /** Finds the highest and lowest sample levels from a section of the audio stream. - /** Adds some events from another buffer to this one. + This will read a block of samples from the stream, and measure the + highest and lowest sample levels from the channels in that section, returning + these as normalised floating-point levels. - @param otherBuffer the buffer containing the events you want to add - @param startSample the lowest sample number in the source buffer for which - events should be added. Any source events whose timestamp is - less than this will be ignored - @param numSamples the valid range of samples from the source buffer for which - events should be added - i.e. events in the source buffer whose - timestamp is greater than or equal to (startSample + numSamples) - will be ignored. If this value is less than 0, all events after - startSample will be taken. - @param sampleDeltaToAdd a value which will be added to the source timestamps of the events - that are added to this buffer + @param startSample the offset into the audio stream to start reading from. It's + ok for this to be beyond the start or end of the stream. + @param numSamples how many samples to read + @param lowestLeft on return, this is the lowest absolute sample from the left channel + @param highestLeft on return, this is the highest absolute sample from the left channel + @param lowestRight on return, this is the lowest absolute sample from the right + channel (if there is one) + @param highestRight on return, this is the highest absolute sample from the right + channel (if there is one) + @see read */ - void addEvents (const MidiBuffer& otherBuffer, - const int startSample, - const int numSamples, - const int sampleDeltaToAdd) throw(); - - /** Returns the sample number of the first event in the buffer. + virtual void readMaxLevels (int64 startSample, + int64 numSamples, + float& lowestLeft, + float& highestLeft, + float& lowestRight, + float& highestRight); - If the buffer's empty, this will just return 0. - */ - int getFirstEventTime() const throw(); + /** Scans the source looking for a sample whose magnitude is in a specified range. - /** Returns the sample number of the last event in the buffer. + This will read from the source, either forwards or backwards between two sample + positions, until it finds a sample whose magnitude lies between two specified levels. - If the buffer's empty, this will just return 0. - */ - int getLastEventTime() const throw(); + If it finds a suitable sample, it returns its position; if not, it will return -1. - /** Exchanges the contents of this buffer with another one. + There's also a minimumConsecutiveSamples setting to help avoid spikes or zero-crossing + points when you're searching for a continuous range of samples - This is a quick operation, because no memory allocating or copying is done, it - just swaps the internal state of the two buffers. + @param startSample the first sample to look at + @param numSamplesToSearch the number of samples to scan. If this value is negative, + the search will go backwards + @param magnitudeRangeMinimum the lowest magnitude (inclusive) that is considered a hit, from 0 to 1.0 + @param magnitudeRangeMaximum the highest magnitude (inclusive) that is considered a hit, from 0 to 1.0 + @param minimumConsecutiveSamples if this is > 0, the method will only look for a sequence + of this many consecutive samples, all of which lie + within the target range. When it finds such a sequence, + it returns the position of the first in-range sample + it found (i.e. the earliest one if scanning forwards, the + latest one if scanning backwards) */ - void swap (MidiBuffer& other); - - /** - Used to iterate through the events in a MidiBuffer. - - Note that altering the buffer while an iterator is using it isn't a - safe operation. + int64 searchForLevel (int64 startSample, + int64 numSamplesToSearch, + const double magnitudeRangeMinimum, + const double magnitudeRangeMaximum, + const int minimumConsecutiveSamples); - @see MidiBuffer - */ - class Iterator - { - public: + /** The sample-rate of the stream. */ + double sampleRate; - /** Creates an Iterator for this MidiBuffer. */ - Iterator (const MidiBuffer& buffer) throw(); + /** The number of bits per sample, e.g. 16, 24, 32. */ + unsigned int bitsPerSample; - /** Destructor. */ - ~Iterator() throw(); + /** The total number of samples in the audio stream. */ + int64 lengthInSamples; - /** Repositions the iterator so that the next event retrieved will be the first - one whose sample position is at greater than or equal to the given position. - */ - void setNextSamplePosition (const int samplePosition) throw(); + /** The total number of channels in the audio stream. */ + unsigned int numChannels; - /** Retrieves a copy of the next event from the buffer. + /** Indicates whether the data is floating-point or fixed. */ + bool usesFloatingPointData; - @param result on return, this will be the message (the MidiMessage's timestamp - is not set) - @param samplePosition on return, this will be the position of the event - @returns true if an event was found, or false if the iterator has reached - the end of the buffer - */ - bool getNextEvent (MidiMessage& result, - int& samplePosition) throw(); + /** A set of metadata values that the reader has pulled out of the stream. - /** Retrieves the next event from the buffer. + Exactly what these values are depends on the format, so you can + check out the format implementation code to see what kind of stuff + they understand. + */ + StringPairArray metadataValues; - @param midiData on return, this pointer will be set to a block of data containing - the midi message. Note that to make it fast, this is a pointer - directly into the MidiBuffer's internal data, so is only valid - temporarily until the MidiBuffer is altered. - @param numBytesOfMidiData on return, this is the number of bytes of data used by the - midi message - @param samplePosition on return, this will be the position of the event - @returns true if an event was found, or false if the iterator has reached - the end of the buffer - */ - bool getNextEvent (const uint8* &midiData, - int& numBytesOfMidiData, - int& samplePosition) throw(); + /** The input stream, for use by subclasses. */ + InputStream* input; - juce_UseDebuggingNewOperator + /** Subclasses must implement this method to perform the low-level read operation. - private: - const MidiBuffer& buffer; - const uint8* data; + Callers should use read() instead of calling this directly. - Iterator (const Iterator&); - const Iterator& operator= (const Iterator&); - }; + @param destSamples the array of destination buffers to fill. Some of these + pointers may be null + @param numDestChannels the number of items in the destSamples array. This + value is guaranteed not to be greater than the number of + channels that this reader object contains + @param startOffsetInDestBuffer the number of samples from the start of the + dest data at which to begin writing + @param startSampleInFile the number of samples into the source data at which + to begin reading. This value is guaranteed to be >= 0. + @param numSamples the number of samples to read + */ + virtual bool readSamples (int** destSamples, + int numDestChannels, + int startOffsetInDestBuffer, + int64 startSampleInFile, + int numSamples) = 0; juce_UseDebuggingNewOperator private: - friend class MidiBuffer::Iterator; - ArrayAllocationBase data; - int bytesUsed; + String formatName; - uint8* findEventAfter (uint8* d, const int samplePosition) const throw(); + AudioFormatReader (const AudioFormatReader&); + const AudioFormatReader& operator= (const AudioFormatReader&); }; -#endif // __JUCE_MIDIBUFFER_JUCEHEADER__ -/********* End of inlined file: juce_MidiBuffer.h *********/ +#endif // __JUCE_AUDIOFORMATREADER_JUCEHEADER__ +/********* End of inlined file: juce_AudioFormatReader.h *********/ -#endif -#ifndef __JUCE_MIDIFILE_JUCEHEADER__ +/********* Start of inlined file: juce_AudioFormatWriter.h *********/ +#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ +#define __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ -/********* Start of inlined file: juce_MidiFile.h *********/ -#ifndef __JUCE_MIDIFILE_JUCEHEADER__ -#define __JUCE_MIDIFILE_JUCEHEADER__ +/********* Start of inlined file: juce_AudioSource.h *********/ +#ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ +#define __JUCE_AUDIOSOURCE_JUCEHEADER__ -/********* Start of inlined file: juce_MidiMessageSequence.h *********/ -#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ -#define __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ +/********* Start of inlined file: juce_AudioSampleBuffer.h *********/ +#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ +#define __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ -/** - A sequence of timestamped midi messages. +class AudioFormatReader; +class AudioFormatWriter; - This allows the sequence to be manipulated, and also to be read from and - written to a standard midi file. +/** + A multi-channel buffer of 32-bit floating point audio samples. - @see MidiMessage, MidiFile */ -class JUCE_API MidiMessageSequence +class JUCE_API AudioSampleBuffer { public: - /** Creates an empty midi sequence object. */ - MidiMessageSequence(); - - /** Creates a copy of another sequence. */ - MidiMessageSequence (const MidiMessageSequence& other); - - /** Replaces this sequence with another one. */ - const MidiMessageSequence& operator= (const MidiMessageSequence& other); - - /** Destructor. */ - ~MidiMessageSequence(); - - /** Structure used to hold midi events in the sequence. + /** Creates a buffer with a specified number of channels and samples. - These structures act as 'handles' on the events as they are moved about in - the list, and make it quick to find the matching note-offs for note-on events. + The contents of the buffer will initially be undefined, so use clear() to + set all the samples to zero. - @see MidiMessageSequence::getEventPointer + The buffer will allocate its memory internally, and this will be released + when the buffer is deleted. */ - class MidiEventHolder - { - public: + AudioSampleBuffer (const int numChannels, + const int numSamples) throw(); - /** Destructor. */ - ~MidiEventHolder(); + /** Creates a buffer using a pre-allocated block of memory. - /** The message itself, whose timestamp is used to specify the event's time. - */ - MidiMessage message; + Note that if the buffer is resized or its number of channels is changed, it + will re-allocate memory internally and copy the existing data to this new area, + so it will then stop directly addressing this memory. - /** The matching note-off event (if this is a note-on event). + @param dataToReferTo a pre-allocated array containing pointers to the data + for each channel that should be used by this buffer. The + buffer will only refer to this memory, it won't try to delete + it when the buffer is deleted or resized. + @param numChannels the number of channels to use - this must correspond to the + number of elements in the array passed in + @param numSamples the number of samples to use - this must correspond to the + size of the arrays passed in + */ + AudioSampleBuffer (float** dataToReferTo, + const int numChannels, + const int numSamples) throw(); - If this isn't a note-on, this pointer will be null. + /** Copies another buffer. - Use the MidiMessageSequence::updateMatchedPairs() method to keep these - note-offs up-to-date after events have been moved around in the sequence - or deleted. - */ - MidiEventHolder* noteOffObject; + This buffer will make its own copy of the other's data, unless the buffer was created + using an external data buffer, in which case boths buffers will just point to the same + shared block of data. + */ + AudioSampleBuffer (const AudioSampleBuffer& other) throw(); - juce_UseDebuggingNewOperator + /** Copies another buffer onto this one. - private: - friend class MidiMessageSequence; - MidiEventHolder (const MidiMessage& message); - }; + This buffer's size will be changed to that of the other buffer. + */ + const AudioSampleBuffer& operator= (const AudioSampleBuffer& other) throw(); - /** Clears the sequence. */ - void clear(); + /** Destructor. - /** Returns the number of events in the sequence. */ - int getNumEvents() const; + This will free any memory allocated by the buffer. + */ + virtual ~AudioSampleBuffer() throw(); - /** Returns a pointer to one of the events. */ - MidiEventHolder* getEventPointer (const int index) const; + /** Returns the number of channels of audio data that this buffer contains. - /** Returns the time of the note-up that matches the note-on at this index. + @see getSampleData + */ + int getNumChannels() const throw() { return numChannels; } - If the event at this index isn't a note-on, it'll just return 0. + /** Returns the number of samples allocated in each of the buffer's channels. - @see MidiMessageSequence::MidiEventHolder::noteOffObject + @see getSampleData */ - double getTimeOfMatchingKeyUp (const int index) const; - - /** Returns the index of the note-up that matches the note-on at this index. + int getNumSamples() const throw() { return size; } - If the event at this index isn't a note-on, it'll just return -1. + /** Returns a pointer one of the buffer's channels. - @see MidiMessageSequence::MidiEventHolder::noteOffObject + For speed, this doesn't check whether the channel number is out of range, + so be careful when using it! */ - int getIndexOfMatchingKeyUp (const int index) const; - - /** Returns the index of an event. */ - int getIndexOf (MidiEventHolder* const event) const; + float* getSampleData (const int channelNumber) const throw() + { + jassert (((unsigned int) channelNumber) < (unsigned int) numChannels); + return channels [channelNumber]; + } - /** Returns the index of the first event on or after the given timestamp. + /** Returns a pointer to a sample in one of the buffer's channels. - If the time is beyond the end of the sequence, this will return the - number of events. + For speed, this doesn't check whether the channel and sample number + are out-of-range, so be careful when using it! */ - int getNextIndexAtTime (const double timeStamp) const; + float* getSampleData (const int channelNumber, + const int sampleOffset) const throw() + { + jassert (((unsigned int) channelNumber) < (unsigned int) numChannels); + jassert (((unsigned int) sampleOffset) < (unsigned int) size); + return channels [channelNumber] + sampleOffset; + } - /** Returns the timestamp of the first event in the sequence. + /** Returns an array of pointers to the channels in the buffer. - @see getEndTime + Don't modify any of the pointers that are returned, and bear in mind that + these will become invalid if the buffer is resized. */ - double getStartTime() const; + float** getArrayOfChannels() const throw() { return channels; } - /** Returns the timestamp of the last event in the sequence. + /** Chages the buffer's size or number of channels. - @see getStartTime - */ - double getEndTime() const; + This can expand or contract the buffer's length, and add or remove channels. - /** Returns the timestamp of the event at a given index. + If keepExistingContent is true, it will try to preserve as much of the + old data as it can in the new buffer. - If the index is out-of-range, this will return 0.0 + If clearExtraSpace is true, then any extra channels or space that is + allocated will be also be cleared. If false, then this space is left + uninitialised. + + If avoidReallocating is true, then changing the buffer's size won't reduce the + amount of memory that is currently allocated (but it will still increase it if + the new size is bigger than the amount it currently has). If this is false, then + a new allocation will be done so that the buffer uses takes up the minimum amount + of memory that it needs. */ - double getEventTime (const int index) const; + void setSize (const int newNumChannels, + const int newNumSamples, + const bool keepExistingContent = false, + const bool clearExtraSpace = false, + const bool avoidReallocating = false) throw(); - /** Inserts a midi message into the sequence. + /** Makes this buffer point to a pre-allocated set of channel data arrays. - The index at which the new message gets inserted will depend on its timestamp, - because the sequence is kept sorted. + There's also a constructor that lets you specify arrays like this, but this + lets you change the channels dynamically. - Remember to call updateMatchedPairs() after adding note-on events. + Note that if the buffer is resized or its number of channels is changed, it + will re-allocate memory internally and copy the existing data to this new area, + so it will then stop directly addressing this memory. - @param newMessage the new message to add (an internal copy will be made) - @param timeAdjustment an optional value to add to the timestamp of the message - that will be inserted - @see updateMatchedPairs + @param dataToReferTo a pre-allocated array containing pointers to the data + for each channel that should be used by this buffer. The + buffer will only refer to this memory, it won't try to delete + it when the buffer is deleted or resized. + @param numChannels the number of channels to use - this must correspond to the + number of elements in the array passed in + @param numSamples the number of samples to use - this must correspond to the + size of the arrays passed in */ - void addEvent (const MidiMessage& newMessage, - double timeAdjustment = 0); + void setDataToReferTo (float** dataToReferTo, + const int numChannels, + const int numSamples) throw(); - /** Deletes one of the events in the sequence. + /** Clears all the samples in all channels. */ + void clear() throw(); - Remember to call updateMatchedPairs() after removing events. + /** Clears a specified region of all the channels. - @param index the index of the event to delete - @param deleteMatchingNoteUp whether to also remove the matching note-off - if the event you're removing is a note-on + For speed, this doesn't check whether the channel and sample number + are in-range, so be careful! */ - void deleteEvent (const int index, - const bool deleteMatchingNoteUp); - - /** Merges another sequence into this one. + void clear (const int startSample, + const int numSamples) throw(); - Remember to call updateMatchedPairs() after using this method. + /** Clears a specified region of just one channel. - @param other the sequence to add from - @param timeAdjustmentDelta an amount to add to the timestamps of the midi events - as they are read from the other sequence - @param firstAllowableDestTime events will not be added if their time is earlier - than this time. (This is after their time has been adjusted - by the timeAdjustmentDelta) - @param endOfAllowableDestTimes events will not be added if their time is equal to - or greater than this time. (This is after their time has - been adjusted by the timeAdjustmentDelta) + For speed, this doesn't check whether the channel and sample number + are in-range, so be careful! */ - void addSequence (const MidiMessageSequence& other, - double timeAdjustmentDelta, - double firstAllowableDestTime, - double endOfAllowableDestTimes); + void clear (const int channel, + const int startSample, + const int numSamples) throw(); - /** Makes sure all the note-on and note-off pairs are up-to-date. + /** Applies a gain multiple to a region of one channel. - Call this after moving messages about or deleting/adding messages, and it - will scan the list and make sure all the note-offs in the MidiEventHolder - structures are pointing at the correct ones. + For speed, this doesn't check whether the channel and sample number + are in-range, so be careful! */ - void updateMatchedPairs(); + void applyGain (const int channel, + const int startSample, + int numSamples, + const float gain) throw(); - /** Copies all the messages for a particular midi channel to another sequence. + /** Applies a gain multiple to a region of all the channels. - @param channelNumberToExtract the midi channel to look for, in the range 1 to 16 - @param destSequence the sequence that the chosen events should be copied to - @param alsoIncludeMetaEvents if true, any meta-events (which don't apply to a specific - channel) will also be copied across. - @see extractSysExMessages + For speed, this doesn't check whether the sample numbers + are in-range, so be careful! */ - void extractMidiChannelMessages (const int channelNumberToExtract, - MidiMessageSequence& destSequence, - const bool alsoIncludeMetaEvents) const; - - /** Copies all midi sys-ex messages to another sequence. + void applyGain (const int startSample, + const int numSamples, + const float gain) throw(); - @param destSequence this is the sequence to which any sys-exes in this sequence - will be added - @see extractMidiChannelMessages - */ - void extractSysExMessages (MidiMessageSequence& destSequence) const; + /** Applies a range of gains to a region of a channel. - /** Removes any messages in this sequence that have a specific midi channel. + The gain that is applied to each sample will vary from + startGain on the first sample to endGain on the last Sample, + so it can be used to do basic fades. - @param channelNumberToRemove the midi channel to look for, in the range 1 to 16 + For speed, this doesn't check whether the sample numbers + are in-range, so be careful! */ - void deleteMidiChannelMessages (const int channelNumberToRemove); + void applyGainRamp (const int channel, + const int startSample, + int numSamples, + float startGain, + float endGain) throw(); - /** Removes any sys-ex messages from this sequence. - */ - void deleteSysExMessages(); + /** Adds samples from another buffer to this one. - /** Adds an offset to the timestamps of all events in the sequence. + @param destChannel the channel within this buffer to add the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source buffer to add from + @param sourceChannel the channel within the source buffer to read from + @param sourceStartSample the offset within the source buffer's channel to start reading samples from + @param numSamples the number of samples to process + @param gainToApplyToSource an optional gain to apply to the source samples before they are + added to this buffer's samples - @param deltaTime the amount to add to each timestamp. + @see copyFrom */ - void addTimeToMessages (const double deltaTime); - - /** Scans through the sequence to determine the state of any midi controllers at - a given time. + void addFrom (const int destChannel, + const int destStartSample, + const AudioSampleBuffer& source, + const int sourceChannel, + const int sourceStartSample, + int numSamples, + const float gainToApplyToSource = 1.0f) throw(); - This will create a sequence of midi controller changes that can be - used to set all midi controllers to the state they would be in at the - specified time within this sequence. + /** Adds samples from an array of floats to one of the channels. - As well as controllers, it will also recreate the midi program number - and pitch bend position. + @param destChannel the channel within this buffer to add the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source data to use + @param numSamples the number of samples to process + @param gainToApplyToSource an optional gain to apply to the source samples before they are + added to this buffer's samples - @param channelNumber the midi channel to look for, in the range 1 to 16. Controllers - for other channels will be ignored. - @param time the time at which you want to find out the state - there are - no explicit units for this time measurement, it's the same units - as used for the timestamps of the messages - @param resultMessages an array to which midi controller-change messages will be added. This - will be the minimum number of controller changes to recreate the - state at the required time. + @see copyFrom */ - void createControllerUpdatesForTime (const int channelNumber, - const double time, - OwnedArray& resultMessages); - - juce_UseDebuggingNewOperator - - /** @internal */ - static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, - const MidiMessageSequence::MidiEventHolder* const second) throw(); - -private: - - friend class MidiComparator; - friend class MidiFile; - OwnedArray list; - - void sort(); -}; - -#endif // __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ -/********* End of inlined file: juce_MidiMessageSequence.h *********/ - -/** - Reads/writes standard midi format files. - - To read a midi file, create a MidiFile object and call its readFrom() method. You - can then get the individual midi tracks from it using the getTrack() method. - - To write a file, create a MidiFile object, add some MidiMessageSequence objects - to it using the addTrack() method, and then call its writeTo() method to stream - it out. + void addFrom (const int destChannel, + const int destStartSample, + const float* source, + int numSamples, + const float gainToApplyToSource = 1.0f) throw(); - @see MidiMessageSequence -*/ -class JUCE_API MidiFile -{ -public: + /** Adds samples from an array of floats, applying a gain ramp to them. - /** Creates an empty MidiFile object. + @param destChannel the channel within this buffer to add the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source data to use + @param numSamples the number of samples to process + @param startGain the gain to apply to the first sample (this is multiplied with + the source samples before they are added to this buffer) + @param endGain the gain to apply to the final sample. The gain is linearly + interpolated between the first and last samples. */ - MidiFile() throw(); - - /** Destructor. */ - ~MidiFile() throw(); - - /** Returns the number of tracks in the file. + void addFromWithRamp (const int destChannel, + const int destStartSample, + const float* source, + int numSamples, + float startGain, + float endGain) throw(); - @see getTrack, addTrack - */ - int getNumTracks() const throw(); + /** Copies samples from another buffer to this one. - /** Returns a pointer to one of the tracks in the file. + @param destChannel the channel within this buffer to copy the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source buffer to read from + @param sourceChannel the channel within the source buffer to read from + @param sourceStartSample the offset within the source buffer's channel to start reading samples from + @param numSamples the number of samples to process - @returns a pointer to the track, or 0 if the index is out-of-range - @see getNumTracks, addTrack + @see addFrom */ - const MidiMessageSequence* getTrack (const int index) const throw(); - - /** Adds a midi track to the file. - - This will make its own internal copy of the sequence that is passed-in. + void copyFrom (const int destChannel, + const int destStartSample, + const AudioSampleBuffer& source, + const int sourceChannel, + const int sourceStartSample, + int numSamples) throw(); - @see getNumTracks, getTrack - */ - void addTrack (const MidiMessageSequence& trackSequence) throw(); + /** Copies samples from an array of floats into one of the channels. - /** Removes all midi tracks from the file. + @param destChannel the channel within this buffer to copy the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source buffer to read from + @param numSamples the number of samples to process - @see getNumTracks + @see addFrom */ - void clear() throw(); - - /** Returns the raw time format code that will be written to a stream. + void copyFrom (const int destChannel, + const int destStartSample, + const float* source, + int numSamples) throw(); - After reading a midi file, this method will return the time-format that - was read from the file's header. It can be changed using the setTicksPerQuarterNote() - or setSmpteTimeFormat() methods. + /** Copies samples from an array of floats into one of the channels, applying a gain to it. - If the value returned is positive, it indicates the number of midi ticks - per quarter-note - see setTicksPerQuarterNote(). + @param destChannel the channel within this buffer to copy the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source buffer to read from + @param numSamples the number of samples to process + @param gain the gain to apply - It it's negative, the upper byte indicates the frames-per-second (but negative), and - the lower byte is the number of ticks per frame - see setSmpteTimeFormat(). + @see addFrom */ - short getTimeFormat() const throw(); + void copyFrom (const int destChannel, + const int destStartSample, + const float* source, + int numSamples, + const float gain) throw(); - /** Sets the time format to use when this file is written to a stream. + /** Copies samples from an array of floats into one of the channels, applying a gain ramp. - If this is called, the file will be written as bars/beats using the - specified resolution, rather than SMPTE absolute times, as would be - used if setSmpteTimeFormat() had been called instead. + @param destChannel the channel within this buffer to copy the samples to + @param destStartSample the start sample within this buffer's channel + @param source the source buffer to read from + @param numSamples the number of samples to process + @param startGain the gain to apply to the first sample (this is multiplied with + the source samples before they are copied to this buffer) + @param endGain the gain to apply to the final sample. The gain is linearly + interpolated between the first and last samples. - @param ticksPerQuarterNote e.g. 96, 960 - @see setSmpteTimeFormat + @see addFrom */ - void setTicksPerQuarterNote (const int ticksPerQuarterNote) throw(); - - /** Sets the time format to use when this file is written to a stream. + void copyFromWithRamp (const int destChannel, + const int destStartSample, + const float* source, + int numSamples, + float startGain, + float endGain) throw(); - If this is called, the file will be written using absolute times, rather - than bars/beats as would be the case if setTicksPerBeat() had been called - instead. + /** Finds the highest and lowest sample values in a given range. - @param framesPerSecond must be 24, 25, 29 or 30 - @param subframeResolution the sub-second resolution, e.g. 4 (midi time code), - 8, 10, 80 (SMPTE bit resolution), or 100. For millisecond - timing, setSmpteTimeFormat (25, 40) - @see setTicksPerBeat + @param channel the channel to read from + @param startSample the start sample within the channel + @param numSamples the number of samples to check + @param minVal on return, the lowest value that was found + @param maxVal on return, the highest value that was found */ - void setSmpteTimeFormat (const int framesPerSecond, - const int subframeResolution) throw(); - - /** Makes a list of all the tempo-change meta-events from all tracks in the midi file. - - Useful for finding the positions of all the tempo changes in a file. + void findMinMax (const int channel, + const int startSample, + int numSamples, + float& minVal, + float& maxVal) const throw(); - @param tempoChangeEvents a list to which all the events will be added + /** Finds the highest absolute sample value within a region of a channel. */ - void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const; - - /** Makes a list of all the time-signature meta-events from all tracks in the midi file. - - Useful for finding the positions of all the tempo changes in a file. + float getMagnitude (const int channel, + const int startSample, + const int numSamples) const throw(); - @param timeSigEvents a list to which all the events will be added + /** Finds the highest absolute sample value within a region on all channels. */ - void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const; - - /** Returns the latest timestamp in any of the tracks. + float getMagnitude (const int startSample, + const int numSamples) const throw(); - (Useful for finding the length of the file). + /** Returns the root mean squared level for a region of a channel. */ - double getLastTimestamp() const; - - /** Reads a midi file format stream. + float getRMSLevel (const int channel, + const int startSample, + const int numSamples) const throw(); - After calling this, you can get the tracks that were read from the file by using the - getNumTracks() and getTrack() methods. + /** Fills a section of the buffer using an AudioReader as its source. - The timestamps of the midi events in the tracks will represent their positions in - terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds() - method. + This will convert the reader's fixed- or floating-point data to + the buffer's floating-point format, and will try to intelligently + cope with mismatches between the number of channels in the reader + and the buffer. - @returns true if the stream was read successfully + @see writeToAudioWriter */ - bool readFrom (InputStream& sourceStream); - - /** Writes the midi tracks as a standard midi file. + void readFromAudioReader (AudioFormatReader* reader, + const int startSample, + const int numSamples, + const int readerStartSample, + const bool useReaderLeftChan, + const bool useReaderRightChan) throw(); - @returns true if the operation succeeded. - */ - bool writeTo (OutputStream& destStream); + /** Writes a section of this buffer to an audio writer. - /** Converts the timestamp of all the midi events from midi ticks to seconds. + This saves you having to mess about with channels or floating/fixed + point conversion. - This will use the midi time format and tempo/time signature info in the - tracks to convert all the timestamps to absolute values in seconds. + @see readFromAudioReader */ - void convertTimestampTicksToSeconds(); + void writeToAudioWriter (AudioFormatWriter* writer, + const int startSample, + const int numSamples) const throw(); juce_UseDebuggingNewOperator - /** @internal */ - static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, - const MidiMessageSequence::MidiEventHolder* const second) throw(); - private: - MidiMessageSequence* tracks [128]; - short numTracks, timeFormat; - - MidiFile (const MidiFile&); - const MidiFile& operator= (const MidiFile&); + int numChannels, size, allocatedBytes; + float** channels; + HeapBlock allocatedData; + float* preallocatedChannelSpace [32]; - void readNextTrack (const char* data, int size); - void writeTrack (OutputStream& mainOut, const int trackNum); + void allocateData(); + void allocateChannels (float** const dataToReferTo); }; -#endif // __JUCE_MIDIFILE_JUCEHEADER__ -/********* End of inlined file: juce_MidiFile.h *********/ - -#endif -#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ - -/********* Start of inlined file: juce_MidiKeyboardState.h *********/ -#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ -#define __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ - -class MidiKeyboardState; +#endif // __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ +/********* End of inlined file: juce_AudioSampleBuffer.h *********/ /** - Receives events from a MidiKeyboardState object. - - @see MidiKeyboardState + Used by AudioSource::getNextAudioBlock(). */ -class JUCE_API MidiKeyboardStateListener +struct JUCE_API AudioSourceChannelInfo { -public: + /** The destination buffer to fill with audio data. - MidiKeyboardStateListener() throw() {} - virtual ~MidiKeyboardStateListener() {} + When the AudioSource::getNextAudioBlock() method is called, the active section + of this buffer should be filled with whatever output the source produces. - /** Called when one of the MidiKeyboardState's keys is pressed. + Only the samples specified by the startSample and numSamples members of this structure + should be affected by the call. - This will be called synchronously when the state is either processing a - buffer in its MidiKeyboardState::processNextMidiBuffer() method, or - when a note is being played with its MidiKeyboardState::noteOn() method. + The contents of the buffer when it is passed to the the AudioSource::getNextAudioBlock() + method can be treated as the input if the source is performing some kind of filter operation, + but should be cleared if this is not the case - the clearActiveBufferRegion() is + a handy way of doing this. - Note that this callback could happen from an audio callback thread, so be - careful not to block, and avoid any UI activity in the callback. + The number of channels in the buffer could be anything, so the AudioSource + must cope with this in whatever way is appropriate for its function. */ - virtual void handleNoteOn (MidiKeyboardState* source, - int midiChannel, int midiNoteNumber, float velocity) = 0; + AudioSampleBuffer* buffer; - /** Called when one of the MidiKeyboardState's keys is released. + /** The first sample in the buffer from which the callback is expected + to write data. */ + int startSample; - This will be called synchronously when the state is either processing a - buffer in its MidiKeyboardState::processNextMidiBuffer() method, or - when a note is being played with its MidiKeyboardState::noteOff() method. + /** The number of samples in the buffer which the callback is expected to + fill with data. */ + int numSamples; - Note that this callback could happen from an audio callback thread, so be - careful not to block, and avoid any UI activity in the callback. - */ - virtual void handleNoteOff (MidiKeyboardState* source, - int midiChannel, int midiNoteNumber) = 0; + /** Convenient method to clear the buffer if the source is not producing any data. */ + void clearActiveBufferRegion() const + { + if (buffer != 0) + buffer->clear (startSample, numSamples); + } }; /** - Represents a piano keyboard, keeping track of which keys are currently pressed. - - This object can parse a stream of midi events, using them to update its idea - of which keys are pressed for each individiual midi channel. - - When keys go up or down, it can broadcast these events to listener objects. + Base class for objects that can produce a continuous stream of audio. - It also allows key up/down events to be triggered with its noteOn() and noteOff() - methods, and midi messages for these events will be merged into the - midi stream that gets processed by processNextMidiBuffer(). + @see AudioFormatReaderSource, ResamplingAudioSource */ -class JUCE_API MidiKeyboardState +class JUCE_API AudioSource { -public: +protected: - MidiKeyboardState(); - ~MidiKeyboardState(); + /** Creates an AudioSource. */ + AudioSource() throw() {} - /** Resets the state of the object. +public: + /** Destructor. */ + virtual ~AudioSource() {} - All internal data for all the channels is reset, but no events are sent as a - result. + /** Tells the source to prepare for playing. - If you want to release any keys that are currently down, and to send out note-up - midi messages for this, use the allNotesOff() method instead. - */ - void reset(); + The source can use this opportunity to initialise anything it needs to. - /** Returns true if the given midi key is currently held down for the given midi channel. + Note that this method could be called more than once in succession without + a matching call to releaseResources(), so make sure your code is robust and + can handle that kind of situation. - The channel number must be between 1 and 16. If you want to see if any notes are - on for a range of channels, use the isNoteOnForChannels() method. + @param samplesPerBlockExpected the number of samples that the source + will be expected to supply each time its + getNextAudioBlock() method is called. This + number may vary slightly, because it will be dependent + on audio hardware callbacks, and these aren't + guaranteed to always use a constant block size, so + the source should be able to cope with small variations. + @param sampleRate the sample rate that the output will be used at - this + is needed by sources such as tone generators. + @see releaseResources, getNextAudioBlock */ - bool isNoteOn (const int midiChannel, const int midiNoteNumber) const throw(); - - /** Returns true if the given midi key is currently held down on any of a set of midi channels. - - The channel mask has a bit set for each midi channel you want to test for - bit - 0 = midi channel 1, bit 1 = midi channel 2, etc. + virtual void prepareToPlay (int samplesPerBlockExpected, + double sampleRate) = 0; - If a note is on for at least one of the specified channels, this returns true. - */ - bool isNoteOnForChannels (const int midiChannelMask, const int midiNoteNumber) const throw(); + /** Allows the source to release anything it no longer needs after playback has stopped. - /** Turns a specified note on. + This will be called when the source is no longer going to have its getNextAudioBlock() + method called, so it should release any spare memory, etc. that it might have + allocated during the prepareToPlay() call. - This will cause a suitable midi note-on event to be injected into the midi buffer during the - next call to processNextMidiBuffer(). + Note that there's no guarantee that prepareToPlay() will actually have been called before + releaseResources(), and it may be called more than once in succession, so make sure your + code is robust and doesn't make any assumptions about when it will be called. - It will also trigger a synchronous callback to the listeners to tell them that the key has - gone down. + @see prepareToPlay, getNextAudioBlock */ - void noteOn (const int midiChannel, const int midiNoteNumber, const float velocity); + virtual void releaseResources() = 0; - /** Turns a specified note off. + /** Called repeatedly to fetch subsequent blocks of audio data. - This will cause a suitable midi note-off event to be injected into the midi buffer during the - next call to processNextMidiBuffer(). + After calling the prepareToPlay() method, this callback will be made each + time the audio playback hardware (or whatever other destination the audio + data is going to) needs another block of data. - It will also trigger a synchronous callback to the listeners to tell them that the key has - gone up. + It will generally be called on a high-priority system thread, or possibly even + an interrupt, so be careful not to do too much work here, as that will cause + audio glitches! - But if the note isn't acutally down for the given channel, this method will in fact do nothing. + @see AudioSourceChannelInfo, prepareToPlay, releaseResources */ - void noteOff (const int midiChannel, const int midiNoteNumber); + virtual void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) = 0; +}; - /** This will turn off any currently-down notes for the given midi channel. +#endif // __JUCE_AUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_AudioSource.h *********/ - If you pass 0 for the midi channel, it will in fact turn off all notes on all channels. +/** + Writes samples to an audio file stream. - Calling this method will make calls to noteOff(), so can trigger synchronous callbacks - and events being added to the midi stream. - */ - void allNotesOff (const int midiChannel); + A subclass that writes a specific type of audio format will be created by + an AudioFormat object. - /** Looks at a key-up/down event and uses it to update the state of this object. + After creating one of these with the AudioFormat::createWriterFor() method + you can call its write() method to store the samples, and then delete it. - To process a buffer full of midi messages, use the processNextMidiBuffer() method - instead. + @see AudioFormat, AudioFormatReader +*/ +class JUCE_API AudioFormatWriter +{ +protected: + + /** Creates an AudioFormatWriter object. + + @param destStream the stream to write to - this will be deleted + by this object when it is no longer needed + @param formatName the description that will be returned by the getFormatName() + method + @param sampleRate the sample rate to use - the base class just stores + this value, it doesn't do anything with it + @param numberOfChannels the number of channels to write - the base class just stores + this value, it doesn't do anything with it + @param bitsPerSample the bit depth of the stream - the base class just stores + this value, it doesn't do anything with it */ - void processNextMidiEvent (const MidiMessage& message); + AudioFormatWriter (OutputStream* const destStream, + const String& formatName, + const double sampleRate, + const unsigned int numberOfChannels, + const unsigned int bitsPerSample); - /** Scans a midi stream for up/down events and adds its own events to it. +public: + /** Destructor. */ + virtual ~AudioFormatWriter(); - This will look for any up/down events and use them to update the internal state, - synchronously making suitable callbacks to the listeners. + /** Returns a description of what type of format this is. - If injectIndirectEvents is true, then midi events to produce the recent noteOn() - and noteOff() calls will be added into the buffer. + E.g. "AIFF file" + */ + const String getFormatName() const throw() { return formatName; } - Only the section of the buffer whose timestamps are between startSample and - (startSample + numSamples) will be affected, and any events added will be placed - between these times. + /** Writes a set of samples to the audio stream. - If you're going to use this method, you'll need to keep calling it regularly for - it to work satisfactorily. + Note that if you're trying to write the contents of an AudioSampleBuffer, you + can use AudioSampleBuffer::writeToAudioWriter(). - To process a single midi event at a time, use the processNextMidiEvent() method - instead. + @param samplesToWrite an array of arrays containing the sample data for + each channel to write. This is a zero-terminated + array of arrays, and can contain a different number + of channels than the actual stream uses, and the + writer should do its best to cope with this. + If the format is fixed-point, each channel will be formatted + as an array of signed integers using the full 32-bit + range -0x80000000 to 0x7fffffff, regardless of the source's + bit-depth. If it is a floating-point format, you should treat + the arrays as arrays of floats, and just cast it to an (int**) + to pass it into the method. + @param numSamples the number of samples to write */ - void processNextMidiBuffer (MidiBuffer& buffer, - const int startSample, - const int numSamples, - const bool injectIndirectEvents); + virtual bool write (const int** samplesToWrite, + int numSamples) = 0; - /** Registers a listener for callbacks when keys go up or down. + /** Reads a section of samples from an AudioFormatReader, and writes these to + the output. - @see removeListener + This will take care of any floating-point conversion that's required to convert + between the two formats. It won't deal with sample-rate conversion, though. + + If numSamplesToRead < 0, it will write the entire length of the reader. + + @returns false if it can't read or write properly during the operation */ - void addListener (MidiKeyboardStateListener* const listener) throw(); + bool writeFromAudioReader (AudioFormatReader& reader, + int64 startSample, + int64 numSamplesToRead); - /** Deregisters a listener. + /** Reads some samples from an AudioSource, and writes these to the output. - @see addListener + The source must already have been initialised with the AudioSource::prepareToPlay() method + + @param source the source to read from + @param numSamplesToRead total number of samples to read and write + @param samplesPerBlock the maximum number of samples to fetch from the source + @returns false if it can't read or write properly during the operation */ - void removeListener (MidiKeyboardStateListener* const listener) throw(); + bool writeFromAudioSource (AudioSource& source, + int numSamplesToRead, + const int samplesPerBlock = 2048); - juce_UseDebuggingNewOperator + /** Returns the sample rate being used. */ + double getSampleRate() const throw() { return sampleRate; } -private: - CriticalSection lock; - uint16 noteStates [128]; - MidiBuffer eventsToAdd; - VoidArray listeners; + /** Returns the number of channels being written. */ + int getNumChannels() const throw() { return numChannels; } - void noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity); - void noteOffInternal (const int midiChannel, const int midiNoteNumber); + /** Returns the bit-depth of the data being written. */ + int getBitsPerSample() const throw() { return bitsPerSample; } - MidiKeyboardState (const MidiKeyboardState&); - const MidiKeyboardState& operator= (const MidiKeyboardState&); -}; + /** Returns true if it's a floating-point format, false if it's fixed-point. */ + bool isFloatingPoint() const throw() { return usesFloatingPointData; } -#endif // __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ -/********* End of inlined file: juce_MidiKeyboardState.h *********/ + juce_UseDebuggingNewOperator -#endif -#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ +protected: + /** The sample rate of the stream. */ + double sampleRate; -/********* Start of inlined file: juce_MidiMessageCollector.h *********/ -#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ -#define __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ + /** The number of channels being written to the stream. */ + unsigned int numChannels; -/********* Start of inlined file: juce_MidiInput.h *********/ -#ifndef __JUCE_MIDIINPUT_JUCEHEADER__ -#define __JUCE_MIDIINPUT_JUCEHEADER__ + /** The bit depth of the file. */ + unsigned int bitsPerSample; -class MidiInput; + /** True if it's a floating-point format, false if it's fixed-point. */ + bool usesFloatingPointData; -/** - Receives midi messages from a midi input device. + /** The output stream for Use by subclasses. */ + OutputStream* output; - This class is overridden to handle incoming midi messages. See the MidiInput - class for more details. +private: + String formatName; +}; - @see MidiInput +#endif // __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ +/********* End of inlined file: juce_AudioFormatWriter.h *********/ + +/** + Subclasses of AudioFormat are used to read and write different audio + file formats. + + @see AudioFormatReader, AudioFormatWriter, WavAudioFormat, AiffAudioFormat */ -class JUCE_API MidiInputCallback +class JUCE_API AudioFormat { public: - /** Destructor. */ - virtual ~MidiInputCallback() {} - /** Receives an incoming message. + /** Destructor. */ + virtual ~AudioFormat(); - A MidiInput object will call this method when a midi event arrives. It'll be - called on a high-priority system thread, so avoid doing anything time-consuming - in here, and avoid making any UI calls. You might find the MidiBuffer class helpful - for queueing incoming messages for use later. + /** Returns the name of this format. - @param source the MidiInput object that generated the message - @param message the incoming message. The message's timestamp is set to a value - equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the - time when the message arrived. + e.g. "WAV file" or "AIFF file" */ - virtual void handleIncomingMidiMessage (MidiInput* source, - const MidiMessage& message) = 0; + const String& getFormatName() const; - /** Notification sent each time a packet of a multi-packet sysex message arrives. + /** Returns all the file extensions that might apply to a file of this format. - If a long sysex message is broken up into multiple packets, this callback is made - for each packet that arrives until the message is finished, at which point - the normal handleIncomingMidiMessage() callback will be made with the entire - message. + The first item will be the one that's preferred when creating a new file. - The message passed in will contain the start of a sysex, but won't be finished - with the terminating 0xf7 byte. + So for a wav file this might just return ".wav"; for an AIFF file it might + return two items, ".aif" and ".aiff" */ - virtual void handlePartialSysexMessage (MidiInput* source, - const uint8* messageData, - const int numBytesSoFar, - const double timestamp) - { - // (this bit is just to avoid compiler warnings about unused variables) - (void) source; (void) messageData; (void) numBytesSoFar; (void) timestamp; - } -}; + const StringArray& getFileExtensions() const; -/** - Represents a midi input device. + /** Returns true if this the given file can be read by this format. - To create one of these, use the static getDevices() method to find out what inputs are - available, and then use the openDevice() method to try to open one. + Subclasses shouldn't do too much work here, just check the extension or + file type. The base class implementation just checks the file's extension + against one of the ones that was registered in the constructor. + */ + virtual bool canHandleFile (const File& fileToTest); - @see MidiOutput -*/ -class JUCE_API MidiInput -{ -public: + /** Returns a set of sample rates that the format can read and write. */ + virtual const Array getPossibleSampleRates() = 0; - /** Returns a list of the available midi input devices. + /** Returns a set of bit depths that the format can read and write. */ + virtual const Array getPossibleBitDepths() = 0; - You can open one of the devices by passing its index into the - openDevice() method. + /** Returns true if the format can do 2-channel audio. */ + virtual bool canDoStereo() = 0; - @see getDefaultDeviceIndex, openDevice - */ - static const StringArray getDevices(); + /** Returns true if the format can do 1-channel audio. */ + virtual bool canDoMono() = 0; - /** Returns the index of the default midi input device to use. + /** Returns true if the format uses compressed data. */ + virtual bool isCompressed(); - This refers to the index in the list returned by getDevices(). - */ - static int getDefaultDeviceIndex(); + /** Returns a list of different qualities that can be used when writing. - /** Tries to open one of the midi input devices. + Non-compressed formats will just return an empty array, but for something + like Ogg-Vorbis or MP3, it might return a list of bit-rates, etc. - This will return a MidiInput object if it manages to open it. You can then - call start() and stop() on this device, and delete it when no longer needed. + When calling createWriterFor(), an index from this array is passed in to + tell the format which option is required. + */ + virtual const StringArray getQualityOptions(); - If the device can't be opened, this will return a null pointer. + /** Tries to create an object that can read from a stream containing audio + data in this format. - @param deviceIndex the index of a device from the list returned by getDevices() - @param callback the object that will receive the midi messages from this device. + The reader object that is returned can be used to read from the stream, and + should then be deleted by the caller. - @see MidiInputCallback, getDevices + @param sourceStream the stream to read from - the AudioFormatReader object + that is returned will delete this stream when it no longer + needs it. + @param deleteStreamIfOpeningFails if no reader can be created, this determines whether this method + should delete the stream object that was passed-in. (If a valid + reader is returned, it will always be in charge of deleting the + stream, so this parameter is ignored) + @see AudioFormatReader */ - static MidiInput* openDevice (int deviceIndex, - MidiInputCallback* callback); + virtual AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails) = 0; -#if JUCE_LINUX || JUCE_MAC || DOXYGEN - /** This will try to create a new midi input device (Not available on Windows). + /** Tries to create an object that can write to a stream with this audio format. - This will attempt to create a new midi input device with the specified name, - for other apps to connect to. + The writer object that is returned can be used to write to the stream, and + should then be deleted by the caller. - Returns 0 if a device can't be created. + If the stream can't be created for some reason (e.g. the parameters passed in + here aren't suitable), this will return 0. - @param deviceName the name to use for the new device - @param callback the object that will receive the midi messages from this device. + @param streamToWriteTo the stream that the data will go to - this will be + deleted by the AudioFormatWriter object when it's no longer + needed. If no AudioFormatWriter can be created by this method, + the stream will NOT be deleted, so that the caller can re-use it + to try to open a different format, etc + @param sampleRateToUse the sample rate for the file, which must be one of the ones + returned by getPossibleSampleRates() + @param numberOfChannels the number of channels - this must be either 1 or 2, and + the choice will depend on the results of canDoMono() and + canDoStereo() + @param bitsPerSample the bits per sample to use - this must be one of the values + returned by getPossibleBitDepths() + @param metadataValues a set of metadata values that the writer should try to write + to the stream. Exactly what these are depends on the format, + and the subclass doesn't actually have to do anything with + them if it doesn't want to. Have a look at the specific format + implementation classes to see possible values that can be + used + @param qualityOptionIndex the index of one of compression qualities returned by the + getQualityOptions() method. If there aren't any quality options + for this format, just pass 0 in this parameter, as it'll be + ignored + @see AudioFormatWriter */ - static MidiInput* createNewDevice (const String& deviceName, - MidiInputCallback* callback); -#endif + virtual AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex) = 0; - /** Destructor. */ - virtual ~MidiInput(); +protected: + /** Creates an AudioFormat object. - /** Returns the name of this device. + @param formatName this sets the value that will be returned by getFormatName() + @param fileExtensions a zero-terminated list of file extensions - this is what will + be returned by getFileExtension() */ - virtual const String getName() const throw() { return name; } + AudioFormat (const String& formatName, + const tchar** const fileExtensions); - /** Allows you to set a custom name for the device, in case you don't like the name - it was given when created. - */ - virtual void setName (const String& newName) throw() { name = newName; } +private: - /** Starts the device running. + String formatName; + StringArray fileExtensions; +}; - After calling this, the device will start sending midi messages to the - MidiInputCallback object that was specified when the openDevice() method - was called. +#endif // __JUCE_AUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_AudioFormat.h *********/ - @see stop - */ - virtual void start(); +/** + Reads and Writes AIFF format audio files. - /** Stops the device running. + @see AudioFormat +*/ +class JUCE_API AiffAudioFormat : public AudioFormat +{ +public: - @see start - */ - virtual void stop(); + /** Creates an format object. */ + AiffAudioFormat(); - juce_UseDebuggingNewOperator + /** Destructor. */ + ~AiffAudioFormat(); -protected: - String name; - void* internal; + const Array getPossibleSampleRates(); + const Array getPossibleBitDepths(); + bool canDoStereo(); + bool canDoMono(); +#if JUCE_MAC + bool canHandleFile (const File& fileToTest); +#endif - MidiInput (const String& name); - MidiInput (const MidiInput&); + AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails); + + AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex); + + juce_UseDebuggingNewOperator }; -#endif // __JUCE_MIDIINPUT_JUCEHEADER__ -/********* End of inlined file: juce_MidiInput.h *********/ +#endif // __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_AiffAudioFormat.h *********/ -/** - Collects incoming realtime MIDI messages and turns them into blocks suitable for - processing by a block-based audio callback. +#endif +#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ - The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback - so it can easily use a midi input or keyboard component as its source. +/********* Start of inlined file: juce_AudioCDBurner.h *********/ +#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ +#define __JUCE_AUDIOCDBURNER_JUCEHEADER__ - @see MidiMessage, MidiInput +#if JUCE_USE_CDBURNER + +/** */ -class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener, - public MidiInputCallback +class AudioCDBurner { public: - /** Creates a MidiMessageCollector. */ - MidiMessageCollector(); + /** Returns a list of available optical drives. - /** Destructor. */ - ~MidiMessageCollector(); + Use openDevice() to open one of the items from this list. + */ + static const StringArray findAvailableDevices(); - /** Clears any messages from the queue. + /** Tries to open one of the optical drives. - You need to call this method before starting to use the collector, so that - it knows the correct sample rate to use. + The deviceIndex is an index into the array returned by findAvailableDevices(). */ - void reset (const double sampleRate); + static AudioCDBurner* openDevice (const int deviceIndex); - /** Takes an incoming real-time message and adds it to the queue. + /** Destructor. */ + ~AudioCDBurner(); - The message's timestamp is taken, and it will be ready for retrieval as part - of the block returned by the next call to removeNextBlockOfMessages(). + /** Returns true if there's a writable disk in the drive. + */ + bool isDiskPresent() const; - This method is fully thread-safe when overlapping calls are made with - removeNextBlockOfMessages(). + /** Returns the number of free blocks on the disk. + + There are 75 blocks per second, at 44100Hz. */ - void addMessageToQueue (const MidiMessage& message); + int getNumAvailableAudioBlocks() const; - /** Removes all the pending messages from the queue as a buffer. + /** Adds a track to be written. - This will also correct the messages' timestamps to make sure they're in - the range 0 to numSamples - 1. + The source passed-in here will be kept by this object, and it will + be used and deleted at some point in the future, either during the + burn() method or when this AudioCDBurner object is deleted. Your caller + method shouldn't keep a reference to it or use it again after passing + it in here. + */ + bool addAudioTrack (AudioSource* source, int numSamples); - This call should be made regularly by something like an audio processing - callback, because the time that it happens is used in calculating the - midi event positions. + /** - This method is fully thread-safe when overlapping calls are made with - addMessageToQueue(). + Return true to cancel the current burn operation */ - void removeNextBlockOfMessages (MidiBuffer& destBuffer, - const int numSamples); + class BurnProgressListener + { + public: + BurnProgressListener() throw() {} + virtual ~BurnProgressListener() {} - /** @internal */ - void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity); - /** @internal */ - void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber); - /** @internal */ - void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); + /** Called at intervals to report on the progress of the AudioCDBurner. + + To cancel the burn, return true from this. + */ + virtual bool audioCDBurnProgress (float proportionComplete) = 0; + }; + + const String burn (BurnProgressListener* listener, + const bool ejectDiscAfterwards, + const bool peformFakeBurnForTesting); juce_UseDebuggingNewOperator private: - double lastCallbackTime; - CriticalSection midiCallbackLock; - MidiBuffer incomingMessages; - double sampleRate; + AudioCDBurner (const int deviceIndex); - MidiMessageCollector (const MidiMessageCollector&); - const MidiMessageCollector& operator= (const MidiMessageCollector&); + void* internal; }; -#endif // __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ -/********* End of inlined file: juce_MidiMessageCollector.h *********/ - #endif -#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ +#endif // __JUCE_AUDIOCDBURNER_JUCEHEADER__ +/********* End of inlined file: juce_AudioCDBurner.h *********/ #endif -#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ +#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ -#endif -#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +/********* Start of inlined file: juce_AudioCDReader.h *********/ +#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ +#define __JUCE_AUDIOCDREADER_JUCEHEADER__ -/********* Start of inlined file: juce_AudioDataConverters.h *********/ -#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ -#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +#if JUCE_USE_CDREADER -/** - A set of routines to convert buffers of 32-bit floating point data to and from - various integer formats. +#if JUCE_MAC -*/ -class JUCE_API AudioDataConverters -{ -public: +#endif - static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); - static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); - - static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); - static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); - - static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); - static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); +/** + A type of AudioFormatReader that reads from an audio CD. - static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); - static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); + One of these can be used to read a CD as if it's one big audio stream. Use the + getPositionOfTrackStart() method to find where the individual tracks are + within the stream. - static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); - static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); + @see AudioFormatReader +*/ +class JUCE_API AudioCDReader : public AudioFormatReader +{ +public: - static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); - static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); + /** Returns a list of names of Audio CDs currently available for reading. - static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); - static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); + If there's a CD drive but no CD in it, this might return an empty list, or + possibly a device that can be opened but which has no tracks, depending + on the platform. - static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); - static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); + @see createReaderForCD + */ + static const StringArray getAvailableCDNames(); - enum DataFormat - { - int16LE, - int16BE, - int24LE, - int24BE, - int32LE, - int32BE, - float32LE, - float32BE, - }; + /** Tries to create an AudioFormatReader that can read from an Audio CD. - static void convertFloatToFormat (const DataFormat destFormat, - const float* source, void* dest, int numSamples); + @param index the index of one of the available CDs - use getAvailableCDNames() + to find out how many there are. + @returns a new AudioCDReader object, or 0 if it couldn't be created. The + caller will be responsible for deleting the object returned. + */ + static AudioCDReader* createReaderForCD (const int index); - static void convertFormatToFloat (const DataFormat sourceFormat, - const void* source, float* dest, int numSamples); + /** Destructor. */ + ~AudioCDReader(); - static void interleaveSamples (const float** source, float* dest, - const int numSamples, const int numChannels); + /** Implementation of the AudioFormatReader method. */ + bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, + int64 startSampleInFile, int numSamples); - static void deinterleaveSamples (const float* source, float** dest, - const int numSamples, const int numChannels); -}; + /** Checks whether the CD has been removed from the drive. + */ + bool isCDStillPresent() const; -#endif // __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ -/********* End of inlined file: juce_AudioDataConverters.h *********/ + /** Returns the total number of tracks (audio + data). + */ + int getNumTracks() const; -#endif -#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ + /** Finds the sample offset of the start of a track. -/********* Start of inlined file: juce_AudioSampleBuffer.h *********/ -#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ -#define __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ + @param trackNum the track number, where 0 is the first track. + */ + int getPositionOfTrackStart (int trackNum) const; -class AudioFormatReader; -class AudioFormatWriter; + /** Returns true if a given track is an audio track. -/** - A multi-channel buffer of 32-bit floating point audio samples. + @param trackNum the track number, where 0 is the first track. + */ + bool isTrackAudio (int trackNum) const; -*/ -class JUCE_API AudioSampleBuffer -{ -public: + /** Refreshes the object's table of contents. - /** Creates a buffer with a specified number of channels and samples. + If the disc has been ejected and a different one put in since this + object was created, this will cause it to update its idea of how many tracks + there are, etc. + */ + void refreshTrackLengths(); - The contents of the buffer will initially be undefined, so use clear() to - set all the samples to zero. + /** Enables scanning for indexes within tracks. - The buffer will allocate its memory internally, and this will be released - when the buffer is deleted. + @see getLastIndex */ - AudioSampleBuffer (const int numChannels, - const int numSamples) throw(); - - /** Creates a buffer using a pre-allocated block of memory. + void enableIndexScanning (bool enabled); - Note that if the buffer is resized or its number of channels is changed, it - will re-allocate memory internally and copy the existing data to this new area, - so it will then stop directly addressing this memory. + /** Returns the index number found during the last read() call. - @param dataToReferTo a pre-allocated array containing pointers to the data - for each channel that should be used by this buffer. The - buffer will only refer to this memory, it won't try to delete - it when the buffer is deleted or resized. - @param numChannels the number of channels to use - this must correspond to the - number of elements in the array passed in - @param numSamples the number of samples to use - this must correspond to the - size of the arrays passed in - */ - AudioSampleBuffer (float** dataToReferTo, - const int numChannels, - const int numSamples) throw(); + Index scanning is turned off by default - turn it on with enableIndexScanning(). - /** Copies another buffer. + Then when the read() method is called, if it comes across an index within that + block, the index number is stored and returned by this method. - This buffer will make its own copy of the other's data, unless the buffer was created - using an external data buffer, in which case boths buffers will just point to the same - shared block of data. - */ - AudioSampleBuffer (const AudioSampleBuffer& other) throw(); + Some devices might not support indexes, of course. - /** Copies another buffer onto this one. + (If you don't know what CD indexes are, it's unlikely you'll ever need them). - This buffer's size will be changed to that of the other buffer. + @see enableIndexScanning */ - const AudioSampleBuffer& operator= (const AudioSampleBuffer& other) throw(); + int getLastIndex() const; - /** Destructor. + /** Scans a track to find the position of any indexes within it. - This will free any memory allocated by the buffer. + @param trackNumber the track to look in, where 0 is the first track on the disc + @returns an array of sample positions of any index points found (not including + the index that marks the start of the track) */ - virtual ~AudioSampleBuffer() throw(); + const Array findIndexesInTrack (const int trackNumber); - /** Returns the number of channels of audio data that this buffer contains. + /** Returns the CDDB id number for the CD. - @see getSampleData + It's not a great way of identifying a disc, but it's traditional. */ - int getNumChannels() const throw() { return numChannels; } + int getCDDBId(); - /** Returns the number of samples allocated in each of the buffer's channels. + /** Tries to eject the disk. - @see getSampleData + Of course this might not be possible, if some other process is using it. */ - int getNumSamples() const throw() { return size; } + void ejectDisk(); - /** Returns a pointer one of the buffer's channels. + juce_UseDebuggingNewOperator - For speed, this doesn't check whether the channel number is out of range, - so be careful when using it! - */ - float* getSampleData (const int channelNumber) const throw() - { - jassert (((unsigned int) channelNumber) < (unsigned int) numChannels); - return channels [channelNumber]; - } +private: - /** Returns a pointer to a sample in one of the buffer's channels. +#if JUCE_MAC + File volumeDir; + OwnedArray tracks; + Array trackStartSamples; + int currentReaderTrack; + AudioFormatReader* reader; + AudioCDReader (const File& volume); +public: + static int compareElements (const File* const, const File* const) throw(); +private: - For speed, this doesn't check whether the channel and sample number - are out-of-range, so be careful when using it! - */ - float* getSampleData (const int channelNumber, - const int sampleOffset) const throw() - { - jassert (((unsigned int) channelNumber) < (unsigned int) numChannels); - jassert (((unsigned int) sampleOffset) < (unsigned int) size); - return channels [channelNumber] + sampleOffset; - } +#elif JUCE_WINDOWS + int numTracks; + int trackStarts[100]; + bool audioTracks [100]; + void* handle; + bool indexingEnabled; + int lastIndex, firstFrameInBuffer, samplesInBuffer; + MemoryBlock buffer; + AudioCDReader (void* handle); + int getIndexAt (int samplePos); - /** Returns an array of pointers to the channels in the buffer. +#elif JUCE_LINUX + AudioCDReader(); +#endif - Don't modify any of the pointers that are returned, and bear in mind that - these will become invalid if the buffer is resized. - */ - float** getArrayOfChannels() const throw() { return channels; } + AudioCDReader (const AudioCDReader&); + const AudioCDReader& operator= (const AudioCDReader&); +}; - /** Chages the buffer's size or number of channels. +#endif +#endif // __JUCE_AUDIOCDREADER_JUCEHEADER__ +/********* End of inlined file: juce_AudioCDReader.h *********/ - This can expand or contract the buffer's length, and add or remove channels. +#endif +#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ - If keepExistingContent is true, it will try to preserve as much of the - old data as it can in the new buffer. +#endif +#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ - If clearExtraSpace is true, then any extra channels or space that is - allocated will be also be cleared. If false, then this space is left - uninitialised. +/********* Start of inlined file: juce_AudioFormatManager.h *********/ +#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ +#define __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ - If avoidReallocating is true, then changing the buffer's size won't reduce the - amount of memory that is currently allocated (but it will still increase it if - the new size is bigger than the amount it currently has). If this is false, then - a new allocation will be done so that the buffer uses takes up the minimum amount - of memory that it needs. - */ - void setSize (const int newNumChannels, - const int newNumSamples, - const bool keepExistingContent = false, - const bool clearExtraSpace = false, - const bool avoidReallocating = false) throw(); +/** + A class for keeping a list of available audio formats, and for deciding which + one to use to open a given file. - /** Makes this buffer point to a pre-allocated set of channel data arrays. + You can either use this class as a singleton object, or create instances of it + yourself. Once created, use its registerFormat() method to tell it which + formats it should use. - There's also a constructor that lets you specify arrays like this, but this - lets you change the channels dynamically. + @see AudioFormat +*/ +class JUCE_API AudioFormatManager +{ +public: - Note that if the buffer is resized or its number of channels is changed, it - will re-allocate memory internally and copy the existing data to this new area, - so it will then stop directly addressing this memory. + /** Creates an empty format manager. - @param dataToReferTo a pre-allocated array containing pointers to the data - for each channel that should be used by this buffer. The - buffer will only refer to this memory, it won't try to delete - it when the buffer is deleted or resized. - @param numChannels the number of channels to use - this must correspond to the - number of elements in the array passed in - @param numSamples the number of samples to use - this must correspond to the - size of the arrays passed in + Before it'll be any use, you'll need to call registerFormat() with all the + formats you want it to be able to recognise. */ - void setDataToReferTo (float** dataToReferTo, - const int numChannels, - const int numSamples) throw(); + AudioFormatManager(); - /** Clears all the samples in all channels. */ - void clear() throw(); + /** Destructor. */ + ~AudioFormatManager(); - /** Clears a specified region of all the channels. + juce_DeclareSingleton (AudioFormatManager, false); - For speed, this doesn't check whether the channel and sample number - are in-range, so be careful! - */ - void clear (const int startSample, - const int numSamples) throw(); + /** Adds a format to the manager's list of available file types. - /** Clears a specified region of just one channel. + The object passed-in will be deleted by this object, so don't keep a pointer + to it! - For speed, this doesn't check whether the channel and sample number - are in-range, so be careful! + If makeThisTheDefaultFormat is true, then the getDefaultFormat() method will + return this one when called. */ - void clear (const int channel, - const int startSample, - const int numSamples) throw(); + void registerFormat (AudioFormat* newFormat, + const bool makeThisTheDefaultFormat); - /** Applies a gain multiple to a region of one channel. + /** Handy method to make it easy to register the formats that come with Juce. - For speed, this doesn't check whether the channel and sample number - are in-range, so be careful! + Currently, this will add WAV and AIFF to the list. */ - void applyGain (const int channel, - const int startSample, - int numSamples, - const float gain) throw(); + void registerBasicFormats(); - /** Applies a gain multiple to a region of all the channels. + /** Clears the list of known formats. */ + void clearFormats(); - For speed, this doesn't check whether the sample numbers - are in-range, so be careful! - */ - void applyGain (const int startSample, - const int numSamples, - const float gain) throw(); + /** Returns the number of currently registered file formats. */ + int getNumKnownFormats() const; - /** Applies a range of gains to a region of a channel. + /** Returns one of the registered file formats. */ + AudioFormat* getKnownFormat (const int index) const; - The gain that is applied to each sample will vary from - startGain on the first sample to endGain on the last Sample, - so it can be used to do basic fades. + /** Looks for which of the known formats is listed as being for a given file + extension. - For speed, this doesn't check whether the sample numbers - are in-range, so be careful! + The extension may have a dot before it, so e.g. ".wav" or "wav" are both ok. */ - void applyGainRamp (const int channel, - const int startSample, - int numSamples, - float startGain, - float endGain) throw(); + AudioFormat* findFormatForFileExtension (const String& fileExtension) const; - /** Adds samples from another buffer to this one. + /** Returns the format which has been set as the default one. - @param destChannel the channel within this buffer to add the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source buffer to add from - @param sourceChannel the channel within the source buffer to read from - @param sourceStartSample the offset within the source buffer's channel to start reading samples from - @param numSamples the number of samples to process - @param gainToApplyToSource an optional gain to apply to the source samples before they are - added to this buffer's samples + You can set a format as being the default when it is registered. It's useful + when you want to write to a file, because the best format may change between + platforms, e.g. AIFF is preferred on the Mac, WAV on Windows. - @see copyFrom + If none has been set as the default, this method will just return the first + one in the list. */ - void addFrom (const int destChannel, - const int destStartSample, - const AudioSampleBuffer& source, - const int sourceChannel, - const int sourceStartSample, - int numSamples, - const float gainToApplyToSource = 1.0f) throw(); - - /** Adds samples from an array of floats to one of the channels. + AudioFormat* getDefaultFormat() const; - @param destChannel the channel within this buffer to add the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source data to use - @param numSamples the number of samples to process - @param gainToApplyToSource an optional gain to apply to the source samples before they are - added to this buffer's samples + /** Returns a set of wildcards for file-matching that contains the extensions for + all known formats. - @see copyFrom + E.g. if might return "*.wav;*.aiff" if it just knows about wavs and aiffs. */ - void addFrom (const int destChannel, - const int destStartSample, - const float* source, - int numSamples, - const float gainToApplyToSource = 1.0f) throw(); + const String getWildcardForAllFormats() const; - /** Adds samples from an array of floats, applying a gain ramp to them. + /** Searches through the known formats to try to create a suitable reader for + this file. - @param destChannel the channel within this buffer to add the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source data to use - @param numSamples the number of samples to process - @param startGain the gain to apply to the first sample (this is multiplied with - the source samples before they are added to this buffer) - @param endGain the gain to apply to the final sample. The gain is linearly - interpolated between the first and last samples. + If none of the registered formats can open the file, it'll return 0. If it + returns a reader, it's the caller's responsibility to delete the reader. */ - void addFromWithRamp (const int destChannel, - const int destStartSample, - const float* source, - int numSamples, - float startGain, - float endGain) throw(); + AudioFormatReader* createReaderFor (const File& audioFile); - /** Copies samples from another buffer to this one. + /** Searches through the known formats to try to create a suitable reader for + this stream. - @param destChannel the channel within this buffer to copy the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source buffer to read from - @param sourceChannel the channel within the source buffer to read from - @param sourceStartSample the offset within the source buffer's channel to start reading samples from - @param numSamples the number of samples to process + The stream object that is passed-in will be deleted by this method or by the + reader that is returned, so the caller should not keep any references to it. - @see addFrom + The stream that is passed-in must be capable of being repositioned so + that all the formats can have a go at opening it. + + If none of the registered formats can open the stream, it'll return 0. If it + returns a reader, it's the caller's responsibility to delete the reader. */ - void copyFrom (const int destChannel, - const int destStartSample, - const AudioSampleBuffer& source, - const int sourceChannel, - const int sourceStartSample, - int numSamples) throw(); + AudioFormatReader* createReaderFor (InputStream* audioFileStream); - /** Copies samples from an array of floats into one of the channels. + juce_UseDebuggingNewOperator - @param destChannel the channel within this buffer to copy the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source buffer to read from - @param numSamples the number of samples to process +private: + VoidArray knownFormats; + int defaultFormatIndex; +}; - @see addFrom - */ - void copyFrom (const int destChannel, - const int destStartSample, - const float* source, - int numSamples) throw(); +#endif // __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_AudioFormatManager.h *********/ - /** Copies samples from an array of floats into one of the channels, applying a gain to it. +#endif +#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ - @param destChannel the channel within this buffer to copy the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source buffer to read from - @param numSamples the number of samples to process - @param gain the gain to apply +#endif +#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ - @see addFrom - */ - void copyFrom (const int destChannel, - const int destStartSample, - const float* source, - int numSamples, - const float gain) throw(); +#endif +#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ - /** Copies samples from an array of floats into one of the channels, applying a gain ramp. +/********* Start of inlined file: juce_AudioSubsectionReader.h *********/ +#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ +#define __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ - @param destChannel the channel within this buffer to copy the samples to - @param destStartSample the start sample within this buffer's channel - @param source the source buffer to read from - @param numSamples the number of samples to process - @param startGain the gain to apply to the first sample (this is multiplied with - the source samples before they are copied to this buffer) - @param endGain the gain to apply to the final sample. The gain is linearly - interpolated between the first and last samples. +/** + This class is used to wrap an AudioFormatReader and only read from a + subsection of the file. - @see addFrom - */ - void copyFromWithRamp (const int destChannel, - const int destStartSample, - const float* source, - int numSamples, - float startGain, - float endGain) throw(); + So if you have a reader which can read a 1000 sample file, you could wrap it + in one of these to only access, e.g. samples 100 to 200, and any samples + outside that will come back as 0. Accessing sample 0 from this reader will + actually read the first sample from the other's subsection, which might + be at a non-zero position. - /** Finds the highest and lowest sample values in a given range. + @see AudioFormatReader +*/ +class JUCE_API AudioSubsectionReader : public AudioFormatReader +{ +public: - @param channel the channel to read from - @param startSample the start sample within the channel - @param numSamples the number of samples to check - @param minVal on return, the lowest value that was found - @param maxVal on return, the highest value that was found - */ - void findMinMax (const int channel, - const int startSample, - int numSamples, - float& minVal, - float& maxVal) const throw(); + /** Creates a AudioSubsectionReader for a given data source. - /** Finds the highest absolute sample value within a region of a channel. - */ - float getMagnitude (const int channel, - const int startSample, - const int numSamples) const throw(); - - /** Finds the highest absolute sample value within a region on all channels. - */ - float getMagnitude (const int startSample, - const int numSamples) const throw(); - - /** Returns the root mean squared level for a region of a channel. - */ - float getRMSLevel (const int channel, - const int startSample, - const int numSamples) const throw(); - - /** Fills a section of the buffer using an AudioReader as its source. - - This will convert the reader's fixed- or floating-point data to - the buffer's floating-point format, and will try to intelligently - cope with mismatches between the number of channels in the reader - and the buffer. - - @see writeToAudioWriter + @param sourceReader the source reader from which we'll be taking data + @param subsectionStartSample the sample within the source reader which will be + mapped onto sample 0 for this reader. + @param subsectionLength the number of samples from the source that will + make up the subsection. If this reader is asked for + any samples beyond this region, it will return zero. + @param deleteSourceWhenDeleted if true, the sourceReader object will be deleted when + this object is deleted. */ - void readFromAudioReader (AudioFormatReader* reader, - const int startSample, - const int numSamples, - const int readerStartSample, - const bool useReaderLeftChan, - const bool useReaderRightChan) throw(); + AudioSubsectionReader (AudioFormatReader* const sourceReader, + const int64 subsectionStartSample, + const int64 subsectionLength, + const bool deleteSourceWhenDeleted); - /** Writes a section of this buffer to an audio writer. + /** Destructor. */ + ~AudioSubsectionReader(); - This saves you having to mess about with channels or floating/fixed - point conversion. + bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, + int64 startSampleInFile, int numSamples); - @see readFromAudioReader - */ - void writeToAudioWriter (AudioFormatWriter* writer, - const int startSample, - const int numSamples) const throw(); + void readMaxLevels (int64 startSample, + int64 numSamples, + float& lowestLeft, + float& highestLeft, + float& lowestRight, + float& highestRight); juce_UseDebuggingNewOperator private: - int numChannels, size, allocatedBytes; - float** channels; - float* allocatedData; - float* preallocatedChannelSpace [32]; + AudioFormatReader* const source; + int64 startSample, length; + const bool deleteSourceWhenDeleted; + + AudioSubsectionReader (const AudioSubsectionReader&); + const AudioSubsectionReader& operator= (const AudioSubsectionReader&); }; -#endif // __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ -/********* End of inlined file: juce_AudioSampleBuffer.h *********/ +#endif // __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ +/********* End of inlined file: juce_AudioSubsectionReader.h *********/ #endif -#ifndef __JUCE_IIRFILTER_JUCEHEADER__ +#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ -/********* Start of inlined file: juce_IIRFilter.h *********/ -#ifndef __JUCE_IIRFILTER_JUCEHEADER__ -#define __JUCE_IIRFILTER_JUCEHEADER__ +/********* Start of inlined file: juce_AudioThumbnail.h *********/ +#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ +#define __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ + +class AudioThumbnailCache; /** - An IIR filter that can perform low, high, or band-pass filtering on an - audio signal. + Makes it easy to quickly draw scaled views of the waveform shape of an + audio file. - @see IIRFilterAudioSource + To use this class, just create an AudioThumbNail class for the file you want + to draw, call setSource to tell it which file or resource to use, then call + drawChannel() to draw it. + + The class will asynchronously scan the wavefile to create its scaled-down view, + so you should make your UI repaint itself as this data comes in. To do this, the + AudioThumbnail is a ChangeBroadcaster, and will broadcast a message when its + listeners should repaint themselves. + + The thumbnail stores an internal low-res version of the wave data, and this can + be loaded and saved to avoid having to scan the file again. + + @see AudioThumbnailCache */ -class JUCE_API IIRFilter +class JUCE_API AudioThumbnail : public ChangeBroadcaster, + public TimeSliceClient, + private Timer { public: - /** Creates a filter. + /** Creates an audio thumbnail. - Initially the filter is inactive, so will have no effect on samples that - you process with it. Use the appropriate method to turn it into the type - of filter needed. + @param sourceSamplesPerThumbnailSample when creating a stored, low-res version + of the audio data, this is the scale at which it should be done. (This + number is the number of original samples that will be averaged for each + low-res sample) + @param formatManagerToUse the audio format manager that is used to open the file + @param cacheToUse an instance of an AudioThumbnailCache - this provides a background + thread and storage that is used to by the thumbnail, and the cache + object can be shared between multiple thumbnails */ - IIRFilter() throw(); - - /** Creates a copy of another filter. */ - IIRFilter (const IIRFilter& other) throw(); + AudioThumbnail (const int sourceSamplesPerThumbnailSample, + AudioFormatManager& formatManagerToUse, + AudioThumbnailCache& cacheToUse); /** Destructor. */ - ~IIRFilter() throw(); - - /** Resets the filter's processing pipeline, ready to start a new stream of data. + ~AudioThumbnail(); - Note that this clears the processing state, but the type of filter and - its coefficients aren't changed. To put a filter into an inactive state, use - the makeInactive() method. - */ - void reset() throw(); + /** Specifies the file or stream that contains the audio file. - /** Performs the filter operation on the given set of samples. - */ - void processSamples (float* const samples, - const int numSamples) throw(); + For a file, just call + @code + setSource (new FileInputSource (file)) + @endcode - /** Processes a single sample, without any locking or checking. + You can pass a zero in here to clear the thumbnail. - Use this if you need fast processing of a single value, but be aware that - this isn't thread-safe in the way that processSamples() is. + The source that is passed in will be deleted by this object when it is no + longer needed */ - float processSingleSampleRaw (const float sample) throw(); + void setSource (InputSource* const newSource); - /** Sets the filter up to act as a low-pass filter. - */ - void makeLowPass (const double sampleRate, - const double frequency) throw(); + /** Reloads the low res thumbnail data from an input stream. - /** Sets the filter up to act as a high-pass filter. + The thumb will automatically attempt to reload itself from its + AudioThumbnailCache. */ - void makeHighPass (const double sampleRate, - const double frequency) throw(); + void loadFrom (InputStream& input); - /** Sets the filter up to act as a low-pass shelf filter with variable Q and gain. + /** Saves the low res thumbnail data to an output stream. - The gain is a scale factor that the low frequencies are multiplied by, so values - greater than 1.0 will boost the low frequencies, values less than 1.0 will - attenuate them. + The thumb will automatically attempt to save itself to its + AudioThumbnailCache after it finishes scanning the wave file. */ - void makeLowShelf (const double sampleRate, - const double cutOffFrequency, - const double Q, - const float gainFactor) throw(); + void saveTo (OutputStream& output) const; - /** Sets the filter up to act as a high-pass shelf filter with variable Q and gain. + /** Returns the number of channels in the file. + */ + int getNumChannels() const throw(); - The gain is a scale factor that the high frequencies are multiplied by, so values - greater than 1.0 will boost the high frequencies, values less than 1.0 will - attenuate them. + /** Returns the length of the audio file, in seconds. */ - void makeHighShelf (const double sampleRate, - const double cutOffFrequency, - const double Q, - const float gainFactor) throw(); + double getTotalLength() const throw(); - /** Sets the filter up to act as a band pass filter centred around a - frequency, with a variable Q and gain. + /** Renders the waveform shape for a channel. - The gain is a scale factor that the centre frequencies are multiplied by, so - values greater than 1.0 will boost the centre frequencies, values less than - 1.0 will attenuate them. - */ - void makeBandPass (const double sampleRate, - const double centreFrequency, - const double Q, - const float gainFactor) throw(); + The waveform will be drawn within the specified rectangle, where startTime + and endTime specify the times within the audio file that should be positioned + at the left and right edges of the rectangle. - /** Clears the filter's coefficients so that it becomes inactive. + The waveform will be scaled vertically so that a full-volume sample will fill + the rectangle vertically, but you can also specify an extra vertical scale factor + with the verticalZoomFactor parameter. */ - void makeInactive() throw(); + void drawChannel (Graphics& g, + int x, int y, int w, int h, + double startTimeSeconds, + double endTimeSeconds, + int channelNum, + const float verticalZoomFactor); - /** Makes this filter duplicate the set-up of another one. + /** Returns true if the low res preview is fully generated. */ - void copyCoefficientsFrom (const IIRFilter& other) throw(); + bool isFullyLoaded() const throw(); + + /** @internal */ + bool useTimeSlice(); + /** @internal */ + void timerCallback(); juce_UseDebuggingNewOperator -protected: - CriticalSection processLock; +private: + AudioFormatManager& formatManagerToUse; + AudioThumbnailCache& cache; + InputSource* source; - void setCoefficients (double c1, double c2, double c3, - double c4, double c5, double c6) throw(); + CriticalSection readerLock; + AudioFormatReader* reader; - bool active; - float coefficients[6]; - float x1, x2, y1, y2; + MemoryBlock data, cachedLevels; + int orginalSamplesPerThumbnailSample; - // (use the copyCoefficientsFrom() method instead of this operator) - const IIRFilter& operator= (const IIRFilter&); + int numChannelsCached, numSamplesCached; + double cachedStart, cachedTimePerPixel; + bool cacheNeedsRefilling; + + void clear(); + + AudioFormatReader* createReader() const; + + void generateSection (AudioFormatReader& reader, + int64 startSample, + int numSamples); + + char* getChannelData (int channel) const; + + void refillCache (const int numSamples, + double startTime, + const double timePerPixel); + + friend class AudioThumbnailCache; + + // true if it needs more callbacks from the readNextBlockFromAudioFile() method + bool initialiseFromAudioFile (AudioFormatReader& reader); + + // returns true if more needs to be read + bool readNextBlockFromAudioFile (AudioFormatReader& reader); }; -#endif // __JUCE_IIRFILTER_JUCEHEADER__ -/********* End of inlined file: juce_IIRFilter.h *********/ +#endif // __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ +/********* End of inlined file: juce_AudioThumbnail.h *********/ #endif -#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ +#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ -/********* Start of inlined file: juce_AudioPlayHead.h *********/ -#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ -#define __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ +/********* Start of inlined file: juce_AudioThumbnailCache.h *********/ +#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ +#define __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ + +struct ThumbnailCacheEntry; /** - A subclass of AudioPlayHead can supply information about the position and - status of a moving play head during audio playback. + An instance of this class is used to manage multiple AudioThumbnail objects. - One of these can be supplied to an AudioProcessor object so that it can find - out about the position of the audio that it is rendering. + The cache runs a single background thread that is shared by all the thumbnails + that need it, and it maintains a set of low-res previews in memory, to avoid + having to re-scan audio files too often. - @see AudioProcessor::setPlayHead, AudioProcessor::getPlayHead + @see AudioThumbnail */ -class JUCE_API AudioPlayHead +class JUCE_API AudioThumbnailCache : public TimeSliceThread { -protected: - - AudioPlayHead() {} - public: - virtual ~AudioPlayHead() {} - /** Frame rate types. */ - enum FrameRateType - { - fps24 = 0, - fps25 = 1, - fps2997 = 2, - fps30 = 3, - fps2997drop = 4, - fps30drop = 5, - fpsUnknown = 99 - }; + /** Creates a cache object. - /** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method. + The maxNumThumbsToStore parameter lets you specify how many previews should + be kept in memory at once. */ - struct CurrentPositionInfo - { - /** The tempo in BPM */ - double bpm; - - /** Time signature numerator, e.g. the 3 of a 3/4 time sig */ - int timeSigNumerator; - /** Time signature denominator, e.g. the 4 of a 3/4 time sig */ - int timeSigDenominator; - - /** The current play position, in seconds from the start of the edit. */ - double timeInSeconds; - - /** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */ - double editOriginTime; + AudioThumbnailCache (const int maxNumThumbsToStore); - /** The current play position in pulses-per-quarter-note. + /** Destructor. */ + ~AudioThumbnailCache(); - This is the number of quarter notes since the edit start. - */ - double ppqPosition; + /** Clears out any stored thumbnails. + */ + void clear(); - /** The position of the start of the last bar, in pulses-per-quarter-note. + /** Reloads the specified thumb if this cache contains the appropriate stored + data. - This is the number of quarter notes from the start of the edit to the - start of the current bar. + This is called automatically by the AudioThumbnail class, so you shouldn't + normally need to call it directly. + */ + bool loadThumb (AudioThumbnail& thumb, const int64 hashCode); - Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If - it's not available, the value will be 0. - */ - double ppqPositionOfLastBarStart; + /** Stores the cachable data from the specified thumb in this cache. - /** The video frame rate, if applicable. */ - FrameRateType frameRate; + This is called automatically by the AudioThumbnail class, so you shouldn't + normally need to call it directly. + */ + void storeThumb (const AudioThumbnail& thumb, const int64 hashCode); - /** True if the transport is currently playing. */ - bool isPlaying; + juce_UseDebuggingNewOperator - /** True if the transport is currently recording. +private: - (When isRecording is true, then isPlaying will also be true). - */ - bool isRecording; - }; + OwnedArray thumbs; + int maxNumThumbsToStore; - /** Fills-in the given structure with details about the transport's - position at the start of the current processing block. - */ - virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0; + friend class AudioThumbnail; + void addThumbnail (AudioThumbnail* const thumb); + void removeThumbnail (AudioThumbnail* const thumb); }; -#endif // __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ -/********* End of inlined file: juce_AudioPlayHead.h *********/ +#endif // __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ +/********* End of inlined file: juce_AudioThumbnailCache.h *********/ #endif -#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ - -/********* Start of inlined file: juce_AudioProcessor.h *********/ -#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSOR_JUCEHEADER__ +#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ -/********* Start of inlined file: juce_AudioProcessorEditor.h *********/ -#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ +/********* Start of inlined file: juce_FlacAudioFormat.h *********/ +#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ +#define __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ -class AudioProcessor; +#if JUCE_USE_FLAC || defined (DOXYGEN) /** - Base class for the component that acts as the GUI for an AudioProcessor. + Reads and writes the lossless-compression FLAC audio format. - Derive your editor component from this class, and create an instance of it - by overriding the AudioProcessor::createEditor() method. + To compile this, you'll need to set the JUCE_USE_FLAC flag in juce_Config.h, + and make sure your include search path and library search path are set up to find + the FLAC header files and static libraries. - @see AudioProcessor, GenericAudioProcessorEditor + @see AudioFormat */ -class JUCE_API AudioProcessorEditor : public Component +class JUCE_API FlacAudioFormat : public AudioFormat { -protected: +public: - /** Creates an editor for the specified processor. - */ - AudioProcessorEditor (AudioProcessor* const owner); + FlacAudioFormat(); + ~FlacAudioFormat(); -public: - /** Destructor. */ - ~AudioProcessorEditor(); + const Array getPossibleSampleRates(); + const Array getPossibleBitDepths(); + bool canDoStereo(); + bool canDoMono(); + bool isCompressed(); - /** Returns a pointer to the processor that this editor represents. */ - AudioProcessor* getAudioProcessor() const throw() { return owner; } + AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails); -private: + AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex); - AudioProcessor* const owner; + juce_UseDebuggingNewOperator }; -#endif // __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ -/********* End of inlined file: juce_AudioProcessorEditor.h *********/ +#endif +#endif // __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_FlacAudioFormat.h *********/ -/********* Start of inlined file: juce_AudioProcessorListener.h *********/ -#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ +#endif +#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ -class AudioProcessor; +/********* Start of inlined file: juce_OggVorbisAudioFormat.h *********/ +#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ +#define __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ + +#if JUCE_USE_OGGVORBIS || defined (DOXYGEN) /** - Base class for listeners that want to know about changes to an AudioProcessor. + Reads and writes the Ogg-Vorbis audio format. - Use AudioProcessor::addListener() to register your listener with an AudioProcessor. + To compile this, you'll need to set the JUCE_USE_OGGVORBIS flag in juce_Config.h, + and make sure your include search path and library search path are set up to find + the Vorbis and Ogg header files and static libraries. - @see AudioProcessor + @see AudioFormat, */ -class JUCE_API AudioProcessorListener +class JUCE_API OggVorbisAudioFormat : public AudioFormat { public: - /** Destructor. */ - virtual ~AudioProcessorListener() {} + OggVorbisAudioFormat(); + ~OggVorbisAudioFormat(); - /** Receives a callback when a parameter is changed. + const Array getPossibleSampleRates(); + const Array getPossibleBitDepths(); + bool canDoStereo(); + bool canDoMono(); + bool isCompressed(); + const StringArray getQualityOptions(); - IMPORTANT NOTE: this will be called synchronously when a parameter changes, and - many audio processors will change their parameter during their audio callback. - This means that not only has your handler code got to be completely thread-safe, - but it's also got to be VERY fast, and avoid blocking. If you need to handle - this event on your message thread, use this callback to trigger an AsyncUpdater - or ChangeBroadcaster which you can respond to on the message thread. - */ - virtual void audioProcessorParameterChanged (AudioProcessor* processor, - int parameterIndex, - float newValue) = 0; + /** Tries to estimate the quality level of an ogg file based on its size. - /** Called to indicate that something else in the plugin has changed, like its - program, number of parameters, etc. + If it can't read the file for some reason, this will just return 1 (medium quality), + otherwise it will return the approximate quality setting that would have been used + to create the file. - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. + @see getQualityOptions */ - virtual void audioProcessorChanged (AudioProcessor* processor) = 0; + int estimateOggFileQuality (const File& source); - /** Indicates that a parameter change gesture has started. + AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails); - E.g. if the user is dragging a slider, this would be called when they first - press the mouse button, and audioProcessorParameterChangeGestureEnd would be - called when they release it. + AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex); - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. + juce_UseDebuggingNewOperator +}; - @see audioProcessorParameterChangeGestureEnd - */ - virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor, - int parameterIndex); - - /** Indicates that a parameter change gesture has finished. - - E.g. if the user is dragging a slider, this would be called when they release - the mouse button. +#endif +#endif // __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_OggVorbisAudioFormat.h *********/ - IMPORTANT NOTE: this will be called synchronously, and many audio processors will - call it during their audio callback. This means that not only has your handler code - got to be completely thread-safe, but it's also got to be VERY fast, and avoid - blocking. If you need to handle this event on your message thread, use this callback - to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the - message thread. +#endif +#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ - @see audioPluginParameterChangeGestureStart - */ - virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor, - int parameterIndex); -}; +/********* Start of inlined file: juce_QuickTimeAudioFormat.h *********/ +#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ +#define __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ -#endif // __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_AudioProcessorListener.h *********/ +#if JUCE_QUICKTIME /** - Base class for audio processing filters or plugins. - - This is intended to act as a base class of audio filter that is general enough to - be wrapped as a VST, AU, RTAS, etc, or used internally. + Uses QuickTime to read the audio track a movie or media file. - It is also used by the plugin hosting code as the wrapper around an instance - of a loaded plugin. + As well as QuickTime movies, this should also manage to open other audio + files that quicktime can understand, like mp3, m4a, etc. - Derive your filter class from this base class, and if you're building a plugin, - you should implement a global function called createPluginFilter() which creates - and returns a new instance of your subclass. + @see AudioFormat */ -class JUCE_API AudioProcessor +class JUCE_API QuickTimeAudioFormat : public AudioFormat { -protected: - - /** Constructor. - - You can also do your initialisation tasks in the initialiseFilterInfo() - call, which will be made after this object has been created. - */ - AudioProcessor(); - public: - /** Destructor. */ - virtual ~AudioProcessor(); - - /** Returns the name of this processor. - */ - virtual const String getName() const = 0; - - /** Called before playback starts, to let the filter prepare itself. - - The sample rate is the target sample rate, and will remain constant until - playback stops. - The estimatedSamplesPerBlock value is a HINT about the typical number of - samples that will be processed for each callback, but isn't any kind - of guarantee. The actual block sizes that the host uses may be different - each time the callback happens, and may be more or less than this value. - */ - virtual void prepareToPlay (double sampleRate, - int estimatedSamplesPerBlock) = 0; + /** Creates a format object. */ + QuickTimeAudioFormat(); - /** Called after playback has stopped, to let the filter free up any resources it - no longer needs. - */ - virtual void releaseResources() = 0; + /** Destructor. */ + ~QuickTimeAudioFormat(); - /** Renders the next block. + const Array getPossibleSampleRates(); + const Array getPossibleBitDepths(); + bool canDoStereo(); + bool canDoMono(); - When this method is called, the buffer contains a number of channels which is - at least as great as the maximum number of input and output channels that - this filter is using. It will be filled with the filter's input data and - should be replaced with the filter's output. + AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails); - So for example if your filter has 2 input channels and 4 output channels, then - the buffer will contain 4 channels, the first two being filled with the - input data. Your filter should read these, do its processing, and replace - the contents of all 4 channels with its output. + AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex); - Or if your filter has 5 inputs and 2 outputs, the buffer will have 5 channels, - all filled with data, and your filter should overwrite the first 2 of these - with its output. But be VERY careful not to write anything to the last 3 - channels, as these might be mapped to memory that the host assumes is read-only! + juce_UseDebuggingNewOperator +}; - Note that if you have more outputs than inputs, then only those channels that - correspond to an input channel are guaranteed to contain sensible data - e.g. - in the case of 2 inputs and 4 outputs, the first two channels contain the input, - but the last two channels may contain garbage, so you should be careful not to - let this pass through without being overwritten or cleared. +#endif +#endif // __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_QuickTimeAudioFormat.h *********/ - Also note that the buffer may have more channels than are strictly necessary, - but your should only read/write from the ones that your filter is supposed to - be using. +#endif +#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ - The number of samples in these buffers is NOT guaranteed to be the same for every - callback, and may be more or less than the estimated value given to prepareToPlay(). - Your code must be able to cope with variable-sized blocks, or you're going to get - clicks and crashes! +/********* Start of inlined file: juce_WavAudioFormat.h *********/ +#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ +#define __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ - If the filter is receiving a midi input, then the midiMessages array will be filled - with the midi messages for this block. Each message's timestamp will indicate the - message's time, as a number of samples from the start of the block. +/** + Reads and Writes WAV format audio files. - Any messages left in the midi buffer when this method has finished are assumed to - be the filter's midi output. This means that your filter should be careful to - clear any incoming messages from the array if it doesn't want them to be passed-on. + @see AudioFormat +*/ +class JUCE_API WavAudioFormat : public AudioFormat +{ +public: - Be very careful about what you do in this callback - it's going to be called by - the audio thread, so any kind of interaction with the UI is absolutely - out of the question. If you change a parameter in here and need to tell your UI to - update itself, the best way is probably to inherit from a ChangeBroadcaster, let - the UI components register as listeners, and then call sendChangeMessage() inside the - processBlock() method to send out an asynchronous message. You could also use - the AsyncUpdater class in a similar way. - */ - virtual void processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) = 0; + /** Creates a format object. */ + WavAudioFormat(); - /** Returns the current AudioPlayHead object that should be used to find - out the state and position of the playhead. + /** Destructor. */ + ~WavAudioFormat(); - You can call this from your processBlock() method, and use the AudioPlayHead - object to get the details about the time of the start of the block currently - being processed. + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - If the host hasn't supplied a playhead object, this will return 0. + @see AudioFormatReader::metadataValues, createWriterFor */ - AudioPlayHead* getPlayHead() const throw() { return playHead; } + static const tchar* const bwavDescription; - /** Returns the current sample rate. + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - This can be called from your processBlock() method - it's not guaranteed - to be valid at any other time, and may return 0 if it's unknown. + @see AudioFormatReader::metadataValues, createWriterFor */ - double getSampleRate() const throw() { return sampleRate; } - - /** Returns the current typical block size that is being used. + static const tchar* const bwavOriginator; - This can be called from your processBlock() method - it's not guaranteed - to be valid at any other time. + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - Remember it's not the ONLY block size that may be used when calling - processBlock, it's just the normal one. The actual block sizes used may be - larger or smaller than this, and will vary between successive calls. + @see AudioFormatReader::metadataValues, createWriterFor */ - int getBlockSize() const throw() { return blockSize; } + static const tchar* const bwavOriginatorRef; - /** Returns the number of input channels that the host will be sending the filter. + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - If writing a plugin, your JucePluginCharacteristics.h file should specify the - number of channels that your filter would prefer to have, and this method lets - you know how many the host is actually using. + Date format is: yyyy-mm-dd - Note that this method is only valid during or after the prepareToPlay() - method call. Until that point, the number of channels will be unknown. + @see AudioFormatReader::metadataValues, createWriterFor */ - int getNumInputChannels() const throw() { return numInputChannels; } + static const tchar* const bwavOriginationDate; - /** Returns the number of output channels that the host will be sending the filter. + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - If writing a plugin, your JucePluginCharacteristics.h file should specify the - number of channels that your filter would prefer to have, and this method lets - you know how many the host is actually using. + Time format is: hh-mm-ss - Note that this method is only valid during or after the prepareToPlay() - method call. Until that point, the number of channels will be unknown. + @see AudioFormatReader::metadataValues, createWriterFor */ - int getNumOutputChannels() const throw() { return numOutputChannels; } - - /** Returns the name of one of the input channels, as returned by the host. + static const tchar* const bwavOriginationTime; - The host might not supply very useful names for channels, and this might be - something like "1", "2", "left", "right", etc. - */ - virtual const String getInputChannelName (const int channelIndex) const = 0; + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - /** Returns the name of one of the output channels, as returned by the host. + This is the number of samples from the start of an edit that the + file is supposed to begin at. Seems like an obvious mistake to + only allow a file to occur in an edit once, but that's the way + it is.. - The host might not supply very useful names for channels, and this might be - something like "1", "2", "left", "right", etc. + @see AudioFormatReader::metadataValues, createWriterFor */ - virtual const String getOutputChannelName (const int channelIndex) const = 0; - - /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ - virtual bool isInputChannelStereoPair (int index) const = 0; + static const tchar* const bwavTimeReference; - /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ - virtual bool isOutputChannelStereoPair (int index) const = 0; + /** Metadata property name used by wav readers and writers for adding + a BWAV chunk to the file. - /** This returns the number of samples delay that the filter imposes on the audio - passing through it. + This is a - The host will call this to find the latency - the filter itself should set this value - by calling setLatencySamples() as soon as it can during its initialisation. + @see AudioFormatReader::metadataValues, createWriterFor */ - int getLatencySamples() const throw() { return latencySamples; } + static const tchar* const bwavCodingHistory; - /** The filter should call this to set the number of samples delay that it introduces. + /** Utility function to fill out the appropriate metadata for a BWAV file. - The filter should call this as soon as it can during initialisation, and can call it - later if the value changes. + This just makes it easier than using the property names directly, and it + fills out the time and date in the right format. */ - void setLatencySamples (const int newLatency); + static const StringPairArray createBWAVMetadata (const String& description, + const String& originator, + const String& originatorRef, + const Time& dateAndTime, + const int64 timeReferenceSamples, + const String& codingHistory); - /** Returns true if the processor wants midi messages. */ - virtual bool acceptsMidi() const = 0; + const Array getPossibleSampleRates(); + const Array getPossibleBitDepths(); + bool canDoStereo(); + bool canDoMono(); - /** Returns true if the processor produces midi messages. */ - virtual bool producesMidi() const = 0; + AudioFormatReader* createReaderFor (InputStream* sourceStream, + const bool deleteStreamIfOpeningFails); - /** This returns a critical section that will automatically be locked while the host - is calling the processBlock() method. + AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, + double sampleRateToUse, + unsigned int numberOfChannels, + int bitsPerSample, + const StringPairArray& metadataValues, + int qualityOptionIndex); - Use it from your UI or other threads to lock access to variables that are used - by the process callback, but obviously be careful not to keep it locked for - too long, because that could cause stuttering playback. If you need to do something - that'll take a long time and need the processing to stop while it happens, use the - suspendProcessing() method instead. + /** Utility function to replace the metadata in a wav file with a new set of values. - @see suspendProcessing + If possible, this cheats by overwriting just the metadata region of the file, rather + than by copying the whole file again. */ - const CriticalSection& getCallbackLock() const throw() { return callbackLock; } - - /** Enables and disables the processing callback. - - If you need to do something time-consuming on a thread and would like to make sure - the audio processing callback doesn't happen until you've finished, use this - to disable the callback and re-enable it again afterwards. + bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); - E.g. - @code - void loadNewPatch() - { - suspendProcessing (true); + juce_UseDebuggingNewOperator +}; - ..do something that takes ages.. +#endif // __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_WavAudioFormat.h *********/ - suspendProcessing (false); - } - @endcode +#endif +#ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ - If the host tries to make an audio callback while processing is suspended, the - filter will return an empty buffer, but won't block the audio thread like it would - do if you use the getCallbackLock() critical section to synchronise access. +/********* Start of inlined file: juce_AudioFormatReaderSource.h *********/ +#ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ +#define __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ - If you're going to use this, your processBlock() method must call isSuspended() and - check whether it's suspended or not. If it is, then it should skip doing any real - processing, either emitting silence or passing the input through unchanged. +/********* Start of inlined file: juce_PositionableAudioSource.h *********/ +#ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ - @see getCallbackLock - */ - void suspendProcessing (const bool shouldBeSuspended); +/** + A type of AudioSource which can be repositioned. - /** Returns true if processing is currently suspended. - @see suspendProcessing - */ - bool isSuspended() const throw() { return suspended; } + The basic AudioSource just streams continuously with no idea of a current + time or length, so the PositionableAudioSource is used for a finite stream + that has a current read position. - /** A plugin can override this to be told when it should reset any playing voices. + @see AudioSource, AudioTransportSource +*/ +class JUCE_API PositionableAudioSource : public AudioSource +{ +protected: - The default implementation does nothing, but a host may call this to tell the - plugin that it should stop any tails or sounds that have been left running. - */ - virtual void reset(); + /** Creates the PositionableAudioSource. */ + PositionableAudioSource() throw() {} - /** Returns true if the processor is being run in an offline mode for rendering. +public: + /** Destructor */ + ~PositionableAudioSource() {} - If the processor is being run live on realtime signals, this returns false. - If the mode is unknown, this will assume it's realtime and return false. + /** Tells the stream to move to a new position. - This value may be unreliable until the prepareToPlay() method has been called, - and could change each time prepareToPlay() is called. + Calling this indicates that the next call to AudioSource::getNextAudioBlock() + should return samples from this position. - @see setNonRealtime() + Note that this may be called on a different thread to getNextAudioBlock(), + so the subclass should make sure it's synchronised. */ - bool isNonRealtime() const throw() { return nonRealtime; } + virtual void setNextReadPosition (int newPosition) = 0; - /** Called by the host to tell this processor whether it's being used in a non-realime - capacity for offline rendering or bouncing. + /** Returns the position from which the next block will be returned. - Whatever value is passed-in will be + @see setNextReadPosition */ - void setNonRealtime (const bool isNonRealtime) throw(); + virtual int getNextReadPosition() const = 0; - /** Creates the filter's UI. + /** Returns the total length of the stream (in samples). */ + virtual int getTotalLength() const = 0; - This can return 0 if you want a UI-less filter, in which case the host may create - a generic UI that lets the user twiddle the parameters directly. + /** Returns true if this source is actually playing in a loop. */ + virtual bool isLooping() const = 0; +}; - If you do want to pass back a component, the component should be created and set to - the correct size before returning it. +#endif // __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_PositionableAudioSource.h *********/ - Remember not to do anything silly like allowing your filter to keep a pointer to - the component that gets created - it could be deleted later without any warning, which - would make your pointer into a dangler. Use the getActiveEditor() method instead. +/** + A type of AudioSource that will read from an AudioFormatReader. - The correct way to handle the connection between an editor component and its - filter is to use something like a ChangeBroadcaster so that the editor can - register itself as a listener, and be told when a change occurs. This lets them - safely unregister themselves when they are deleted. + @see PositionableAudioSource, AudioTransportSource, BufferingAudioSource +*/ +class JUCE_API AudioFormatReaderSource : public PositionableAudioSource +{ +public: - Here are a few things to bear in mind when writing an editor: + /** Creates an AudioFormatReaderSource for a given reader. - - Initially there won't be an editor, until the user opens one, or they might - not open one at all. Your filter mustn't rely on it being there. - - An editor object may be deleted and a replacement one created again at any time. - - It's safe to assume that an editor will be deleted before its filter. + @param sourceReader the reader to use as the data source + @param deleteReaderWhenThisIsDeleted if true, the reader passed-in will be deleted + when this object is deleted; if false it will be + left up to the caller to manage its lifetime */ - virtual AudioProcessorEditor* createEditor() = 0; + AudioFormatReaderSource (AudioFormatReader* const sourceReader, + const bool deleteReaderWhenThisIsDeleted); - /** Returns the active editor, if there is one. + /** Destructor. */ + ~AudioFormatReaderSource(); - Bear in mind this can return 0, even if an editor has previously been - opened. - */ - AudioProcessorEditor* getActiveEditor() const throw() { return activeEditor; } + /** Toggles loop-mode. - /** Returns the active editor, or if there isn't one, it will create one. + If set to true, it will continuously loop the input source. If false, + it will just emit silence after the source has finished. - This may call createEditor() internally to create the component. + @see isLooping */ - AudioProcessorEditor* createEditorIfNeeded(); + void setLooping (const bool shouldLoop) throw(); - /** This must return the correct value immediately after the object has been - created, and mustn't change the number of parameters later. - */ - virtual int getNumParameters() = 0; + /** Returns whether loop-mode is turned on or not. */ + bool isLooping() const { return looping; } - /** Returns the name of a particular parameter. */ - virtual const String getParameterName (int parameterIndex) = 0; + /** Returns the reader that's being used. */ + AudioFormatReader* getAudioFormatReader() const throw() { return reader; } - /** Called by the host to find out the value of one of the filter's parameters. + /** Implementation of the AudioSource method. */ + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - The host will expect the value returned to be between 0 and 1.0. + /** Implementation of the AudioSource method. */ + void releaseResources(); - This could be called quite frequently, so try to make your code efficient. - It's also likely to be called by non-UI threads, so the code in here should - be thread-aware. - */ - virtual float getParameter (int parameterIndex) = 0; + /** Implementation of the AudioSource method. */ + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - /** Returns the value of a parameter as a text string. */ - virtual const String getParameterText (int parameterIndex) = 0; + /** Implements the PositionableAudioSource method. */ + void setNextReadPosition (int newPosition); - /** The host will call this method to change the value of one of the filter's parameters. + /** Implements the PositionableAudioSource method. */ + int getNextReadPosition() const; - The host may call this at any time, including during the audio processing - callback, so the filter has to process this very fast and avoid blocking. + /** Implements the PositionableAudioSource method. */ + int getTotalLength() const; - If you want to set the value of a parameter internally, e.g. from your - editor component, then don't call this directly - instead, use the - setParameterNotifyingHost() method, which will also send a message to - the host telling it about the change. If the message isn't sent, the host - won't be able to automate your parameters properly. + juce_UseDebuggingNewOperator - The value passed will be between 0 and 1.0. - */ - virtual void setParameter (int parameterIndex, - float newValue) = 0; +private: + AudioFormatReader* reader; + bool deleteReader; - /** Your filter can call this when it needs to change one of its parameters. + int volatile nextPlayPos; + bool volatile looping; - This could happen when the editor or some other internal operation changes - a parameter. This method will call the setParameter() method to change the - value, and will then send a message to the host telling it about the change. + void readBufferSection (int start, int length, AudioSampleBuffer& buffer, int startSample); - Note that to make sure the host correctly handles automation, you should call - the beginParameterChangeGesture() and endParameterChangeGesture() methods to - tell the host when the user has started and stopped changing the parameter. - */ - void setParameterNotifyingHost (int parameterIndex, - float newValue); + AudioFormatReaderSource (const AudioFormatReaderSource&); + const AudioFormatReaderSource& operator= (const AudioFormatReaderSource&); +}; - /** Returns true if the host can automate this parameter. +#endif // __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_AudioFormatReaderSource.h *********/ - By default, this returns true for all parameters. - */ - virtual bool isParameterAutomatable (int parameterIndex) const; +#endif +#ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ - /** Should return true if this parameter is a "meta" parameter. +#endif +#ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ - A meta-parameter is a parameter that changes other params. It is used - by some hosts (e.g. AudioUnit hosts). +/********* Start of inlined file: juce_AudioSourcePlayer.h *********/ +#ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ +#define __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ - By default this returns false. - */ - virtual bool isMetaParameter (int parameterIndex) const; +/********* Start of inlined file: juce_AudioIODevice.h *********/ +#ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__ +#define __JUCE_AUDIOIODEVICE_JUCEHEADER__ - /** Sends a signal to the host to tell it that the user is about to start changing this - parameter. +class AudioIODevice; - This allows the host to know when a parameter is actively being held by the user, and - it may use this information to help it record automation. +/** + One of these is passed to an AudioIODevice object to stream the audio data + in and out. - If you call this, it must be matched by a later call to endParameterChangeGesture(). - */ - void beginParameterChangeGesture (int parameterIndex); + The AudioIODevice will repeatedly call this class's audioDeviceIOCallback() + method on its own high-priority audio thread, when it needs to send or receive + the next block of data. - /** Tells the host that the user has finished changing this parameter. + @see AudioIODevice, AudioDeviceManager +*/ +class JUCE_API AudioIODeviceCallback +{ +public: + /** Destructor. */ + virtual ~AudioIODeviceCallback() {} - This allows the host to know when a parameter is actively being held by the user, and - it may use this information to help it record automation. + /** Processes a block of incoming and outgoing audio data. - A call to this method must follow a call to beginParameterChangeGesture(). + The subclass's implementation should use the incoming audio for whatever + purposes it needs to, and must fill all the output channels with the next + block of output data before returning. + + The channel data is arranged with the same array indices as the channel name + array returned by AudioIODevice::getOutputChannelNames(), but those channels + that aren't specified in AudioIODevice::open() will have a null pointer for their + associated channel, so remember to check for this. + + @param inputChannelData a set of arrays containing the audio data for each + incoming channel - this data is valid until the function + returns. There will be one channel of data for each input + channel that was enabled when the audio device was opened + (see AudioIODevice::open()) + @param numInputChannels the number of pointers to channel data in the + inputChannelData array. + @param outputChannelData a set of arrays which need to be filled with the data + that should be sent to each outgoing channel of the device. + There will be one channel of data for each output channel + that was enabled when the audio device was opened (see + AudioIODevice::open()) + The initial contents of the array is undefined, so the + callback function must fill all the channels with zeros if + its output is silence. Failing to do this could cause quite + an unpleasant noise! + @param numOutputChannels the number of pointers to channel data in the + outputChannelData array. + @param numSamples the number of samples in each channel of the input and + output arrays. The number of samples will depend on the + audio device's buffer size and will usually remain constant, + although this isn't guaranteed, so make sure your code can + cope with reasonable changes in the buffer size from one + callback to the next. */ - void endParameterChangeGesture (int parameterIndex); + virtual void audioDeviceIOCallback (const float** inputChannelData, + int numInputChannels, + float** outputChannelData, + int numOutputChannels, + int numSamples) = 0; - /** The filter can call this when something (apart from a parameter value) has changed. + /** Called to indicate that the device is about to start calling back. - It sends a hint to the host that something like the program, number of parameters, - etc, has changed, and that it should update itself. + This will be called just before the audio callbacks begin, either when this + callback has just been added to an audio device, or after the device has been + restarted because of a sample-rate or block-size change. + + You can use this opportunity to find out the sample rate and block size + that the device is going to use by calling the AudioIODevice::getCurrentSampleRate() + and AudioIODevice::getCurrentBufferSizeSamples() on the supplied pointer. + + @param device the audio IO device that will be used to drive the callback. + Note that if you're going to store this this pointer, it is + only valid until the next time that audioDeviceStopped is called. */ - void updateHostDisplay(); + virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; - /** Returns the number of preset programs the filter supports. + /** Called to indicate that the device has stopped. + */ + virtual void audioDeviceStopped() = 0; +}; - The value returned must be valid as soon as this object is created, and - must not change over its lifetime. +/** + Base class for an audio device with synchronised input and output channels. - This value shouldn't be less than 1. + Subclasses of this are used to implement different protocols such as DirectSound, + ASIO, CoreAudio, etc. + + To create one of these, you'll need to use the AudioIODeviceType class - see the + documentation for that class for more info. + + For an easier way of managing audio devices and their settings, have a look at the + AudioDeviceManager class. + + @see AudioIODeviceType, AudioDeviceManager +*/ +class JUCE_API AudioIODevice +{ +public: + /** Destructor. */ + virtual ~AudioIODevice(); + + /** Returns the device's name, (as set in the constructor). */ + const String& getName() const throw() { return name; } + + /** Returns the type of the device. + + E.g. "CoreAudio", "ASIO", etc. - this comes from the AudioIODeviceType that created it. */ - virtual int getNumPrograms() = 0; + const String& getTypeName() const throw() { return typeName; } - /** Returns the number of the currently active program. + /** Returns the names of all the available output channels on this device. + To find out which of these are currently in use, call getActiveOutputChannels(). */ - virtual int getCurrentProgram() = 0; + virtual const StringArray getOutputChannelNames() = 0; - /** Called by the host to change the current program. + /** Returns the names of all the available input channels on this device. + To find out which of these are currently in use, call getActiveInputChannels(). */ - virtual void setCurrentProgram (int index) = 0; + virtual const StringArray getInputChannelNames() = 0; - /** Must return the name of a given program. */ - virtual const String getProgramName (int index) = 0; + /** Returns the number of sample-rates this device supports. - /** Called by the host to rename a program. + To find out which rates are available on this device, use this method to + find out how many there are, and getSampleRate() to get the rates. + + @see getSampleRate */ - virtual void changeProgramName (int index, const String& newName) = 0; + virtual int getNumSampleRates() = 0; - /** The host will call this method when it wants to save the filter's internal state. + /** Returns one of the sample-rates this device supports. - This must copy any info about the filter's state into the block of memory provided, - so that the host can store this and later restore it using setStateInformation(). + To find out which rates are available on this device, use getNumSampleRates() to + find out how many there are, and getSampleRate() to get the individual rates. - Note that there's also a getCurrentProgramStateInformation() method, which only - stores the current program, not the state of the entire filter. + The sample rate is set by the open() method. - See also the helper function copyXmlToBinary() for storing settings as XML. + (Note that for DirectSound some rates might not work, depending on combinations + of i/o channels that are being opened). - @see getCurrentProgramStateInformation + @see getNumSampleRates */ - virtual void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData) = 0; + virtual double getSampleRate (int index) = 0; - /** The host will call this method if it wants to save the state of just the filter's - current program. + /** Returns the number of sizes of buffer that are available. - Unlike getStateInformation, this should only return the current program's state. + @see getBufferSizeSamples, getDefaultBufferSize + */ + virtual int getNumBufferSizesAvailable() = 0; - Not all hosts support this, and if you don't implement it, the base class - method just calls getStateInformation() instead. If you do implement it, be - sure to also implement getCurrentProgramStateInformation. + /** Returns one of the possible buffer-sizes. - @see getStateInformation, setCurrentProgramStateInformation + @param index the index of the buffer-size to use, from 0 to getNumBufferSizesAvailable() - 1 + @returns a number of samples + @see getNumBufferSizesAvailable, getDefaultBufferSize */ - virtual void getCurrentProgramStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); + virtual int getBufferSizeSamples (int index) = 0; - /** This must restore the filter's state from a block of data previously created - using getStateInformation(). + /** Returns the default buffer-size to use. - Note that there's also a setCurrentProgramStateInformation() method, which tries - to restore just the current program, not the state of the entire filter. + @returns a number of samples + @see getNumBufferSizesAvailable, getBufferSizeSamples + */ + virtual int getDefaultBufferSize() = 0; - See also the helper function getXmlFromBinary() for loading settings as XML. + /** Tries to open the device ready to play. - @see setCurrentProgramStateInformation + @param inputChannels a BitArray in which a set bit indicates that the corresponding + input channel should be enabled + @param outputChannels a BitArray in which a set bit indicates that the corresponding + output channel should be enabled + @param sampleRate the sample rate to try to use - to find out which rates are + available, see getNumSampleRates() and getSampleRate() + @param bufferSizeSamples the size of i/o buffer to use - to find out the available buffer + sizes, see getNumBufferSizesAvailable() and getBufferSizeSamples() + @returns an error description if there's a problem, or an empty string if it succeeds in + opening the device + @see close */ - virtual void setStateInformation (const void* data, int sizeInBytes) = 0; + virtual const String open (const BitArray& inputChannels, + const BitArray& outputChannels, + double sampleRate, + int bufferSizeSamples) = 0; - /** The host will call this method if it wants to restore the state of just the filter's - current program. + /** Closes and releases the device if it's open. */ + virtual void close() = 0; - Not all hosts support this, and if you don't implement it, the base class - method just calls setStateInformation() instead. If you do implement it, be - sure to also implement getCurrentProgramStateInformation. + /** Returns true if the device is still open. - @see setStateInformation, getCurrentProgramStateInformation + A device might spontaneously close itself if something goes wrong, so this checks if + it's still open. */ - virtual void setCurrentProgramStateInformation (const void* data, int sizeInBytes); + virtual bool isOpen() = 0; - /** Adds a listener that will be called when an aspect of this processor changes. */ - void addListener (AudioProcessorListener* const newListener) throw(); + /** Starts the device actually playing. - /** Removes a previously added listener. */ - void removeListener (AudioProcessorListener* const listenerToRemove) throw(); + This must be called after the device has been opened. - /** Not for public use - this is called before deleting an editor component. */ - void editorBeingDeleted (AudioProcessorEditor* const editor) throw(); + @param callback the callback to use for streaming the data. + @see AudioIODeviceCallback, open + */ + virtual void start (AudioIODeviceCallback* callback) = 0; - /** Not for public use - this is called to initialise the processor. */ - void setPlayHead (AudioPlayHead* const newPlayHead) throw(); + /** Stops the device playing. - /** Not for public use - this is called to initialise the processor before playing. */ - void setPlayConfigDetails (const int numIns, const int numOuts, - const double sampleRate, - const int blockSize) throw(); + Once a device has been started, this will stop it. Any pending calls to the + callback class will be flushed before this method returns. + */ + virtual void stop() = 0; - juce_UseDebuggingNewOperator + /** Returns true if the device is still calling back. -protected: + The device might mysteriously stop, so this checks whether it's + still playing. + */ + virtual bool isPlaying() = 0; - /** Helper function that just converts an xml element into a binary blob. + /** Returns the last error that happened if anything went wrong. */ + virtual const String getLastError() = 0; - Use this in your filter's getStateInformation() method if you want to - store its state as xml. + /** Returns the buffer size that the device is currently using. - Then use getXmlFromBinary() to reverse this operation and retrieve the XML - from a binary blob. + If the device isn't actually open, this value doesn't really mean much. */ - static void copyXmlToBinary (const XmlElement& xml, - JUCE_NAMESPACE::MemoryBlock& destData); + virtual int getCurrentBufferSizeSamples() = 0; - /** Retrieves an XML element that was stored as binary with the copyXmlToBinary() method. + /** Returns the sample rate that the device is currently using. - This might return 0 if the data's unsuitable or corrupted. Otherwise it will return - an XmlElement object that the caller must delete when no longer needed. + If the device isn't actually open, this value doesn't really mean much. */ - static XmlElement* getXmlFromBinary (const void* data, - const int sizeInBytes); + virtual double getCurrentSampleRate() = 0; - /** @internal */ - AudioPlayHead* playHead; + /** Returns the device's current physical bit-depth. - /** @internal */ - void sendParamChangeMessageToListeners (const int parameterIndex, const float newValue); + If the device isn't actually open, this value doesn't really mean much. + */ + virtual int getCurrentBitDepth() = 0; -private: - VoidArray listeners; - AudioProcessorEditor* activeEditor; - double sampleRate; - int blockSize, numInputChannels, numOutputChannels, latencySamples; - bool suspended, nonRealtime; - CriticalSection callbackLock, listenerLock; + /** Returns a mask showing which of the available output channels are currently + enabled. + @see getOutputChannelNames + */ + virtual const BitArray getActiveOutputChannels() const = 0; -#ifdef JUCE_DEBUG - BitArray changingParams; -#endif + /** Returns a mask showing which of the available input channels are currently + enabled. + @see getInputChannelNames + */ + virtual const BitArray getActiveInputChannels() const = 0; - AudioProcessor (const AudioProcessor&); - const AudioProcessor& operator= (const AudioProcessor&); -}; + /** Returns the device's output latency. -#endif // __JUCE_AUDIOPROCESSOR_JUCEHEADER__ -/********* End of inlined file: juce_AudioProcessor.h *********/ + This is the delay in samples between a callback getting a block of data, and + that data actually getting played. + */ + virtual int getOutputLatencyInSamples() = 0; -#endif -#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ + /** Returns the device's input latency. -#endif -#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ + This is the delay in samples between some audio actually arriving at the soundcard, + and the callback getting passed this block of data. + */ + virtual int getInputLatencyInSamples() = 0; -/********* Start of inlined file: juce_AudioProcessorGraph.h *********/ -#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ + /** True if this device can show a pop-up control panel for editing its settings. -/********* Start of inlined file: juce_AudioPluginFormatManager.h *********/ -#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ -#define __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ + This is generally just true of ASIO devices. If true, you can call showControlPanel() + to display it. + */ + virtual bool hasControlPanel() const; -/********* Start of inlined file: juce_AudioPluginFormat.h *********/ -#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ -#define __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ + /** Shows a device-specific control panel if there is one. -/********* Start of inlined file: juce_AudioPluginInstance.h *********/ -#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ -#define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ + This should only be called for devices which return true from hasControlPanel(). + */ + virtual bool showControlPanel(); -/********* Start of inlined file: juce_PluginDescription.h *********/ -#ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ -#define __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ +protected: + /** Creates a device, setting its name and type member variables. */ + AudioIODevice (const String& deviceName, + const String& typeName); -/** - A small class to represent some facts about a particular type of plugin. + /** @internal */ + String name, typeName; +}; - This class is for storing and managing the details about a plugin without - actually having to load an instance of it. +#endif // __JUCE_AUDIOIODEVICE_JUCEHEADER__ +/********* End of inlined file: juce_AudioIODevice.h *********/ - A KnownPluginList contains a list of PluginDescription objects. +/** + Wrapper class to continuously stream audio from an audio source to an + AudioIODevice. - @see KnownPluginList + This object acts as an AudioIODeviceCallback, so can be attached to an + output device, and will stream audio from an AudioSource. */ -class JUCE_API PluginDescription +class JUCE_API AudioSourcePlayer : public AudioIODeviceCallback { public: - PluginDescription() throw(); - PluginDescription (const PluginDescription& other) throw(); - const PluginDescription& operator= (const PluginDescription& other) throw(); - ~PluginDescription() throw(); - - /** The name of the plugin. */ - String name; + /** Creates an empty AudioSourcePlayer. */ + AudioSourcePlayer(); - /** The plugin format, e.g. "VST", "AudioUnit", etc. - */ - String pluginFormatName; + /** Destructor. - /** A category, such as "Dynamics", "Reverbs", etc. + Make sure this object isn't still being used by an AudioIODevice before + deleting it! */ - String category; - - /** The manufacturer. */ - String manufacturerName; + virtual ~AudioSourcePlayer(); - /** The version. This string doesn't have any particular format. */ - String version; + /** Changes the current audio source to play from. - /** Either the file containing the plugin module, or some other unique way - of identifying it. + If the source passed in is already being used, this method will do nothing. + If the source is not null, its prepareToPlay() method will be called + before it starts being used for playback. - E.g. for an AU, this would be an ID string that the component manager - could use to retrieve the plugin. For a VST, it's the file path. - */ - String fileOrIdentifier; + If there's another source currently playing, its releaseResources() method + will be called after it has been swapped for the new one. - /** The last time the plugin file was changed. - This is handy when scanning for new or changed plugins. + @param newSource the new source to use - this will NOT be deleted + by this object when no longer needed, so it's the + caller's responsibility to manage it. */ - Time lastFileModTime; - - /** A unique ID for the plugin. + void setSource (AudioSource* newSource); - Note that this might not be unique between formats, e.g. a VST and some - other format might actually have the same id. + /** Returns the source that's playing. - @see createIdentifierString + May return 0 if there's no source. */ - int uid; - - /** True if the plugin identifies itself as a synthesiser. */ - bool isInstrument; + AudioSource* getCurrentSource() const throw() { return source; } - /** The number of inputs. */ - int numInputChannels; + /** Sets a gain to apply to the audio data. */ + void setGain (const float newGain) throw(); - /** The number of outputs. */ - int numOutputChannels; + /** Implementation of the AudioIODeviceCallback method. */ + void audioDeviceIOCallback (const float** inputChannelData, + int totalNumInputChannels, + float** outputChannelData, + int totalNumOutputChannels, + int numSamples); - /** Returns true if the two descriptions refer the the same plugin. + /** Implementation of the AudioIODeviceCallback method. */ + void audioDeviceAboutToStart (AudioIODevice* device); - This isn't quite as simple as them just having the same file (because of - shell plugins). - */ - bool isDuplicateOf (const PluginDescription& other) const; + /** Implementation of the AudioIODeviceCallback method. */ + void audioDeviceStopped(); - /** Returns a string that can be saved and used to uniquely identify the - plugin again. + juce_UseDebuggingNewOperator - This contains less info than the XML encoding, and is independent of the - plugin's file location, so can be used to store a plugin ID for use - across different machines. - */ - const String createIdentifierString() const throw(); +private: - /** Creates an XML object containing these details. + CriticalSection readLock; + AudioSource* source; + double sampleRate; + int bufferSize; + float* channels [128]; + float* outputChans [128]; + const float* inputChans [128]; + AudioSampleBuffer tempBuffer; + float lastGain, gain; - @see loadFromXml - */ - XmlElement* createXml() const; + AudioSourcePlayer (const AudioSourcePlayer&); + const AudioSourcePlayer& operator= (const AudioSourcePlayer&); +}; - /** Reloads the info in this structure from an XML record that was previously - saved with createXML(). +#endif // __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ +/********* End of inlined file: juce_AudioSourcePlayer.h *********/ - Returns true if the XML was a valid plugin description. - */ - bool loadFromXml (const XmlElement& xml); +#endif +#ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ - juce_UseDebuggingNewOperator -}; +/********* Start of inlined file: juce_AudioTransportSource.h *********/ +#ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ +#define __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ -#endif // __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ -/********* End of inlined file: juce_PluginDescription.h *********/ +/********* Start of inlined file: juce_BufferingAudioSource.h *********/ +#ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ /** - Base class for an active instance of a plugin. + An AudioSource which takes another source as input, and buffers it using a thread. - This derives from the AudioProcessor class, and adds some extra functionality - that helps when wrapping dynamically loaded plugins. + Create this as a wrapper around another thread, and it will read-ahead with + a background thread to smooth out playback. You can either create one of these + directly, or use it indirectly using an AudioTransportSource. - @see AudioProcessor, AudioPluginFormat + @see PositionableAudioSource, AudioTransportSource */ -class JUCE_API AudioPluginInstance : public AudioProcessor +class JUCE_API BufferingAudioSource : public PositionableAudioSource { public: - /** Destructor. + /** Creates a BufferingAudioSource. - Make sure that you delete any UI components that belong to this plugin before - deleting the plugin. + @param source the input source to read from + @param deleteSourceWhenDeleted if true, then the input source object will + be deleted when this object is deleted + @param numberOfSamplesToBuffer the size of buffer to use for reading ahead */ - virtual ~AudioPluginInstance(); + BufferingAudioSource (PositionableAudioSource* source, + const bool deleteSourceWhenDeleted, + int numberOfSamplesToBuffer); - /** Fills-in the appropriate parts of this plugin description object. + /** Destructor. + + The input source may be deleted depending on whether the deleteSourceWhenDeleted + flag was set in the constructor. */ - virtual void fillInPluginDescription (PluginDescription& description) const = 0; + ~BufferingAudioSource(); - juce_UseDebuggingNewOperator + /** Implementation of the AudioSource method. */ + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); -protected: - AudioPluginInstance(); + /** Implementation of the AudioSource method. */ + void releaseResources(); - AudioPluginInstance (const AudioPluginInstance&); - const AudioPluginInstance& operator= (const AudioPluginInstance&); -}; + /** Implementation of the AudioSource method. */ + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); -#endif // __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ -/********* End of inlined file: juce_AudioPluginInstance.h *********/ + /** Implements the PositionableAudioSource method. */ + void setNextReadPosition (int newPosition); -class PluginDescription; + /** Implements the PositionableAudioSource method. */ + int getNextReadPosition() const; -/** - The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc. + /** Implements the PositionableAudioSource method. */ + int getTotalLength() const { return source->getTotalLength(); } - Use the static getNumFormats() and getFormat() calls to find the types - of format that are available. -*/ -class JUCE_API AudioPluginFormat -{ -public: + /** Implements the PositionableAudioSource method. */ + bool isLooping() const { return source->isLooping(); } - /** Destructor. */ - virtual ~AudioPluginFormat(); + juce_UseDebuggingNewOperator - /** Returns the format name. +private: - E.g. "VST", "AudioUnit", etc. - */ - virtual const String getName() const = 0; + PositionableAudioSource* source; + bool deleteSourceWhenDeleted; + int numberOfSamplesToBuffer; + AudioSampleBuffer buffer; + CriticalSection bufferStartPosLock; + int volatile bufferValidStart, bufferValidEnd, nextPlayPos; + bool wasSourceLooping; + double volatile sampleRate; - /** This tries to create descriptions for all the plugin types available in - a binary module file. + friend class SharedBufferingAudioSourceThread; + bool readNextBufferChunk(); + void readBufferSection (int start, int length, int bufferOffset); - The file will be some kind of DLL or bundle. + BufferingAudioSource (const BufferingAudioSource&); + const BufferingAudioSource& operator= (const BufferingAudioSource&); +}; - Normally there will only be one type returned, but some plugins - (e.g. VST shells) can use a single DLL to create a set of different plugin - subtypes, so in that case, each subtype is returned as a separate object. - */ - virtual void findAllTypesForFile (OwnedArray & results, - const String& fileOrIdentifier) = 0; +#endif // __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_BufferingAudioSource.h *********/ - /** Tries to recreate a type from a previously generated PluginDescription. +/********* Start of inlined file: juce_ResamplingAudioSource.h *********/ +#ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ - @see PluginDescription::createInstance - */ - virtual AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc) = 0; +/** + A type of AudioSource that takes an input source and changes its sample rate. - /** Should do a quick check to see if this file or directory might be a plugin of - this format. + @see AudioSource +*/ +class JUCE_API ResamplingAudioSource : public AudioSource +{ +public: - This is for searching for potential files, so it shouldn't actually try to - load the plugin or do anything time-consuming. - */ - virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; + /** Creates a ResamplingAudioSource for a given input source. - /** Returns a readable version of the name of the plugin that this identifier refers to. + @param inputSource the input source to read from + @param deleteInputWhenDeleted if true, the input source will be deleted when + this object is deleted */ - virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; + ResamplingAudioSource (AudioSource* const inputSource, + const bool deleteInputWhenDeleted); - /** Checks whether this plugin could possibly be loaded. + /** Destructor. */ + ~ResamplingAudioSource(); - It doesn't actually need to load it, just to check whether the file or component - still exists. - */ - virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; + /** Changes the resampling ratio. - /** Searches a suggested set of directories for any plugins in this format. + (This value can be changed at any time, even while the source is running). - The path might be ignored, e.g. by AUs, which are found by the OS rather - than manually. + @param samplesInPerOutputSample if set to 1.0, the input is passed through; higher + values will speed it up; lower values will slow it + down. The ratio must be greater than 0 */ - virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, - const bool recursive) = 0; + void setResamplingRatio (const double samplesInPerOutputSample); - /** Returns the typical places to look for this kind of plugin. + /** Returns the current resampling ratio. - Note that if this returns no paths, it means that the format can't be scanned-for - (i.e. it's an internal format that doesn't live in files) + This is the value that was set by setResamplingRatio(). */ - virtual const FileSearchPath getDefaultLocationsToSearch() = 0; + double getResamplingRatio() const throw() { return ratio; } + + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void releaseResources(); + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); juce_UseDebuggingNewOperator -protected: - AudioPluginFormat() throw(); +private: + AudioSource* const input; + const bool deleteInputWhenDeleted; + double ratio, lastRatio; + AudioSampleBuffer buffer; + int bufferPos, sampsInBuffer; + double subSampleOffset; + double coefficients[6]; + CriticalSection ratioLock; - AudioPluginFormat (const AudioPluginFormat&); - const AudioPluginFormat& operator= (const AudioPluginFormat&); + void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); + void createLowPass (const double proportionalRate); + + struct FilterState + { + double x1, x2, y1, y2; + }; + + FilterState filterStates[2]; + void resetFilters(); + + void applyFilter (float* samples, int num, FilterState& fs); + + ResamplingAudioSource (const ResamplingAudioSource&); + const ResamplingAudioSource& operator= (const ResamplingAudioSource&); }; -#endif // __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_AudioPluginFormat.h *********/ +#endif // __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_ResamplingAudioSource.h *********/ /** - This maintains a list of known AudioPluginFormats. + An AudioSource that takes a PositionableAudioSource and allows it to be + played, stopped, started, etc. - @see AudioPluginFormat + This can also be told use a buffer and background thread to read ahead, and + if can correct for different sample-rates. + + You may want to use one of these along with an AudioSourcePlayer and AudioIODevice + to control playback of an audio file. + + @see AudioSource, AudioSourcePlayer */ -class JUCE_API AudioPluginFormatManager : public DeletedAtShutdown +class JUCE_API AudioTransportSource : public PositionableAudioSource, + public ChangeBroadcaster { public: - AudioPluginFormatManager() throw(); + /** Creates an AudioTransportSource. + + After creating one of these, use the setSource() method to select an input source. + */ + AudioTransportSource(); /** Destructor. */ - ~AudioPluginFormatManager() throw(); + ~AudioTransportSource(); - juce_DeclareSingleton_SingleThreaded (AudioPluginFormatManager, false); + /** Sets the reader that is being used as the input source. - /** Adds any formats that it knows about, e.g. VST. + This will stop playback, reset the position to 0 and change to the new reader. + + The source passed in will not be deleted by this object, so must be managed by + the caller. + + @param newSource the new input source to use. This may be zero + @param readAheadBufferSize a size of buffer to use for reading ahead. If this + is zero, no reading ahead will be done; if it's + greater than zero, a BufferingAudioSource will be used + to do the reading-ahead + @param sourceSampleRateToCorrectFor if this is non-zero, it specifies the sample + rate of the source, and playback will be sample-rate + adjusted to maintain playback at the correct pitch. If + this is 0, no sample-rate adjustment will be performed */ - void addDefaultFormats(); + void setSource (PositionableAudioSource* const newSource, + int readAheadBufferSize = 0, + double sourceSampleRateToCorrectFor = 0.0); - /** Returns the number of types of format that are available. + /** Changes the current playback position in the source stream. - Use getFormat() to get one of them. + The next time the getNextAudioBlock() method is called, this + is the time from which it'll read data. + + @see getPosition */ - int getNumFormats() throw(); + void setPosition (double newPosition); - /** Returns one of the available formats. + /** Returns the position that the next data block will be read from - @see getNumFormats + This is a time in seconds. */ - AudioPluginFormat* getFormat (const int index) throw(); + double getCurrentPosition() const; - /** Adds a format to the list. + /** Returns true if the player has stopped because its input stream ran out of data. + */ + bool hasStreamFinished() const throw() { return inputStreamEOF; } - The object passed in will be owned and deleted by the manager. + /** Starts playing (if a source has been selected). + + If it starts playing, this will send a message to any ChangeListeners + that are registered with this object. */ - void addFormat (AudioPluginFormat* const format) throw(); + void start(); - /** Tries to load the type for this description, by trying all the formats - that this manager knows about. + /** Stops playing. - The caller is responsible for deleting the object that is returned. + If it's actually playing, this will send a message to any ChangeListeners + that are registered with this object. + */ + void stop(); - If it can't load the plugin, it returns 0 and leaves a message in the - errorMessage string. + /** Returns true if it's currently playing. */ + bool isPlaying() const throw() { return playing; } + + /** Changes the gain to apply to the output. + + @param newGain a factor by which to multiply the outgoing samples, + so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc. */ - AudioPluginInstance* createPluginInstance (const PluginDescription& description, - String& errorMessage) const; + void setGain (const float newGain) throw(); - /** Checks that the file or component for this plugin actually still exists. + /** Returns the current gain setting. - (This won't try to load the plugin) + @see setGain */ - bool doesPluginStillExist (const PluginDescription& description) const; + float getGain() const throw() { return gain; } + + /** Implementation of the AudioSource method. */ + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + + /** Implementation of the AudioSource method. */ + void releaseResources(); + + /** Implementation of the AudioSource method. */ + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + + /** Implements the PositionableAudioSource method. */ + void setNextReadPosition (int newPosition); + + /** Implements the PositionableAudioSource method. */ + int getNextReadPosition() const; + + /** Implements the PositionableAudioSource method. */ + int getTotalLength() const; + + /** Implements the PositionableAudioSource method. */ + bool isLooping() const; juce_UseDebuggingNewOperator private: - OwnedArray formats; + PositionableAudioSource* source; + ResamplingAudioSource* resamplerSource; + BufferingAudioSource* bufferingSource; + PositionableAudioSource* positionableSource; + AudioSource* masterSource; - AudioPluginFormatManager (const AudioPluginFormatManager&); - const AudioPluginFormatManager& operator= (const AudioPluginFormatManager&); + CriticalSection callbackLock; + float volatile gain, lastGain; + bool volatile playing, stopped; + double sampleRate, sourceSampleRate; + int blockSize, readAheadBufferSize; + bool isPrepared, inputStreamEOF; + + AudioTransportSource (const AudioTransportSource&); + const AudioTransportSource& operator= (const AudioTransportSource&); }; -#endif // __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_AudioPluginFormatManager.h *********/ +#endif // __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_AudioTransportSource.h *********/ -/********* Start of inlined file: juce_KnownPluginList.h *********/ -#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ -#define __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ +#endif +#ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ -/********* Start of inlined file: juce_PopupMenu.h *********/ -#ifndef __JUCE_POPUPMENU_JUCEHEADER__ -#define __JUCE_POPUPMENU_JUCEHEADER__ +#endif +#ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ -/********* Start of inlined file: juce_PopupMenuCustomComponent.h *********/ -#ifndef __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ -#define __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_ChannelRemappingAudioSource.h *********/ +#ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ -/** A user-defined copmonent that can appear inside one of the rows of a popup menu. +/** + An AudioSource that takes the audio from another source, and re-maps its + input and output channels to a different arrangement. - @see PopupMenu::addCustomItem + You can use this to increase or decrease the number of channels that an + audio source uses, or to re-order those channels. + + Call the reset() method before using it to set up a default mapping, and then + the setInputChannelMapping() and setOutputChannelMapping() methods to + create an appropriate mapping, otherwise no channels will be connected and + it'll produce silence. + + @see AudioSource */ -class JUCE_API PopupMenuCustomComponent : public Component +class ChannelRemappingAudioSource : public AudioSource { public: + + /** Creates a remapping source that will pass on audio from the given input. + + @param source the input source to use. Make sure that this doesn't + get deleted before the ChannelRemappingAudioSource object + @param deleteSourceWhenDeleted if true, the input source will be deleted + when this object is deleted, if false, the caller is + responsible for its deletion + */ + ChannelRemappingAudioSource (AudioSource* const source, + const bool deleteSourceWhenDeleted); + /** Destructor. */ - ~PopupMenuCustomComponent(); + ~ChannelRemappingAudioSource(); - /** Chooses the size that this component would like to have. + /** Specifies a number of channels that this audio source must produce from its + getNextAudioBlock() callback. + */ + void setNumberOfChannelsToProduce (const int requiredNumberOfChannels) throw(); - Note that the size which this method returns isn't necessarily the one that - the menu will give it, as it will be stretched to fit the other items in - the menu. + /** Clears any mapped channels. + + After this, no channels are mapped, so this object will produce silence. Create + some mappings with setInputChannelMapping() and setOutputChannelMapping(). */ - virtual void getIdealSize (int& idealWidth, - int& idealHeight) = 0; + void clearAllMappings() throw(); - /** Dismisses the menu indicating that this item has been chosen. + /** Creates an input channel mapping. - This will cause the menu to exit from its modal state, returning - this item's id as the result. + When the getNextAudioBlock() method is called, the data in channel sourceChannelIndex of the incoming + data will be sent to destChannelIndex of our input source. + + @param destChannelIndex the index of an input channel in our input audio source (i.e. the + source specified when this object was created). + @param sourceChannelIndex the index of the input channel in the incoming audio data buffer + during our getNextAudioBlock() callback */ - void triggerMenuItem(); + void setInputChannelMapping (const int destChannelIndex, + const int sourceChannelIndex) throw(); - /** Returns true if this item should be highlighted because the mouse is - over it. + /** Creates an output channel mapping. - You can call this method in your paint() method to find out whether - to draw a highlight. + When the getNextAudioBlock() method is called, the data returned in channel sourceChannelIndex by + our input audio source will be copied to channel destChannelIndex of the final buffer. + + @param sourceChannelIndex the index of an output channel coming from our input audio source + (i.e. the source specified when this object was created). + @param destChannelIndex the index of the output channel in the incoming audio data buffer + during our getNextAudioBlock() callback */ - bool isItemHighlighted() const throw() { return isHighlighted; } + void setOutputChannelMapping (const int sourceChannelIndex, + const int destChannelIndex) throw(); -protected: - /** Constructor. + /** Returns the channel from our input that will be sent to channel inputChannelIndex of + our input audio source. + */ + int getRemappedInputChannel (const int inputChannelIndex) const throw(); - If isTriggeredAutomatically is true, then the menu will automatically detect - a click on this component and use that to trigger it. If it's false, then it's - up to your class to manually trigger the item if it wants to. + /** Returns the output channel to which channel outputChannelIndex of our input audio + source will be sent to. */ - PopupMenuCustomComponent (const bool isTriggeredAutomatically = true); + int getRemappedOutputChannel (const int outputChannelIndex) const throw(); -private: - friend class MenuItemInfo; - friend class MenuItemComponent; - friend class PopupMenuWindow; - int refCount_; - bool isHighlighted, isTriggeredAutomatically; + /** Returns an XML object to encapsulate the state of the mappings. - PopupMenuCustomComponent (const PopupMenuCustomComponent&); - const PopupMenuCustomComponent& operator= (const PopupMenuCustomComponent&); -}; + @see restoreFromXml + */ + XmlElement* createXml() const throw(); -#endif // __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_PopupMenuCustomComponent.h *********/ + /** Restores the mappings from an XML object created by createXML(). -/** Creates and displays a popup-menu. + @see createXml + */ + void restoreFromXml (const XmlElement& e) throw(); - To show a popup-menu, you create one of these, add some items to it, then - call its show() method, which returns the id of the item the user selects. + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void releaseResources(); + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - E.g. @code - void MyWidget::mouseDown (const MouseEvent& e) - { - PopupMenu m; - m.addItem (1, "item 1"); - m.addItem (2, "item 2"); + juce_UseDebuggingNewOperator - const int result = m.show(); +private: + int requiredNumberOfChannels; + Array remappedInputs, remappedOutputs; - if (result == 0) - { - // user dismissed the menu without picking anything - } - else if (result == 1) - { - // user picked item 1 - } - else if (result == 2) - { - // user picked item 2 - } - } - @endcode + AudioSource* const source; + const bool deleteSourceWhenDeleted; - Submenus are easy too: @code + AudioSampleBuffer buffer; + AudioSourceChannelInfo remappedInfo; - void MyWidget::mouseDown (const MouseEvent& e) - { - PopupMenu subMenu; - subMenu.addItem (1, "item 1"); - subMenu.addItem (2, "item 2"); + CriticalSection lock; - PopupMenu mainMenu; - mainMenu.addItem (3, "item 3"); - mainMenu.addSubMenu ("other choices", subMenu); + ChannelRemappingAudioSource (const ChannelRemappingAudioSource&); + const ChannelRemappingAudioSource& operator= (const ChannelRemappingAudioSource&); +}; - const int result = m.show(); +#endif // __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_ChannelRemappingAudioSource.h *********/ - ...etc - } - @endcode +#endif +#ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ + +/********* Start of inlined file: juce_IIRFilterAudioSource.h *********/ +#ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ + +/********* Start of inlined file: juce_IIRFilter.h *********/ +#ifndef __JUCE_IIRFILTER_JUCEHEADER__ +#define __JUCE_IIRFILTER_JUCEHEADER__ + +/** + An IIR filter that can perform low, high, or band-pass filtering on an + audio signal. + + @see IIRFilterAudioSource */ -class JUCE_API PopupMenu +class JUCE_API IIRFilter { public: - /** Creates an empty popup menu. */ - PopupMenu() throw(); + /** Creates a filter. - /** Creates a copy of another menu. */ - PopupMenu (const PopupMenu& other) throw(); + Initially the filter is inactive, so will have no effect on samples that + you process with it. Use the appropriate method to turn it into the type + of filter needed. + */ + IIRFilter() throw(); + + /** Creates a copy of another filter. */ + IIRFilter (const IIRFilter& other) throw(); /** Destructor. */ - ~PopupMenu() throw(); + ~IIRFilter() throw(); - /** Copies this menu from another one. */ - const PopupMenu& operator= (const PopupMenu& other) throw(); + /** Resets the filter's processing pipeline, ready to start a new stream of data. - /** Resets the menu, removing all its items. */ - void clear() throw(); + Note that this clears the processing state, but the type of filter and + its coefficients aren't changed. To put a filter into an inactive state, use + the makeInactive() method. + */ + void reset() throw(); - /** Appends a new text item for this menu to show. + /** Performs the filter operation on the given set of samples. + */ + void processSamples (float* const samples, + const int numSamples) throw(); - @param itemResultId the number that will be returned from the show() method - if the user picks this item. The value should never be - zero, because that's used to indicate that the user didn't - select anything. - @param itemText the text to show. - @param isActive if false, the item will be shown 'greyed-out' and can't be - picked - @param isTicked if true, the item will be shown with a tick next to it - @param iconToUse if this is non-zero, it should be an image that will be - displayed to the left of the item. This method will take its - own copy of the image passed-in, so there's no need to keep - it hanging around. + /** Processes a single sample, without any locking or checking. - @see addSeparator, addColouredItem, addCustomItem, addSubMenu + Use this if you need fast processing of a single value, but be aware that + this isn't thread-safe in the way that processSamples() is. */ - void addItem (const int itemResultId, - const String& itemText, - const bool isActive = true, - const bool isTicked = false, - const Image* const iconToUse = 0) throw(); + float processSingleSampleRaw (const float sample) throw(); - /** Adds an item that represents one of the commands in a command manager object. + /** Sets the filter up to act as a low-pass filter. + */ + void makeLowPass (const double sampleRate, + const double frequency) throw(); - @param commandManager the manager to use to trigger the command and get information - about it - @param commandID the ID of the command - @param displayName if this is non-empty, then this string will be used instead of - the command's registered name + /** Sets the filter up to act as a high-pass filter. */ - void addCommandItem (ApplicationCommandManager* commandManager, - const int commandID, - const String& displayName = String::empty) throw(); + void makeHighPass (const double sampleRate, + const double frequency) throw(); - /** Appends a text item with a special colour. + /** Sets the filter up to act as a low-pass shelf filter with variable Q and gain. - This is the same as addItem(), but specifies a colour to use for the - text, which will override the default colours that are used by the - current look-and-feel. See addItem() for a description of the parameters. + The gain is a scale factor that the low frequencies are multiplied by, so values + greater than 1.0 will boost the low frequencies, values less than 1.0 will + attenuate them. */ - void addColouredItem (const int itemResultId, - const String& itemText, - const Colour& itemTextColour, - const bool isActive = true, - const bool isTicked = false, - const Image* const iconToUse = 0) throw(); - - /** Appends a custom menu item. + void makeLowShelf (const double sampleRate, + const double cutOffFrequency, + const double Q, + const float gainFactor) throw(); - This will add a user-defined component to use as a menu item. The component - passed in will be deleted by this menu when it's no longer needed. + /** Sets the filter up to act as a high-pass shelf filter with variable Q and gain. - @see PopupMenuCustomComponent + The gain is a scale factor that the high frequencies are multiplied by, so values + greater than 1.0 will boost the high frequencies, values less than 1.0 will + attenuate them. */ - void addCustomItem (const int itemResultId, - PopupMenuCustomComponent* const customComponent) throw(); + void makeHighShelf (const double sampleRate, + const double cutOffFrequency, + const double Q, + const float gainFactor) throw(); - /** Appends a custom menu item that can't be used to trigger a result. + /** Sets the filter up to act as a band pass filter centred around a + frequency, with a variable Q and gain. - This will add a user-defined component to use as a menu item. Unlike the - addCustomItem() method that takes a PopupMenuCustomComponent, this version - can't trigger a result from it, so doesn't take a menu ID. It also doesn't - delete the component when it's finished, so it's the caller's responsibility - to manage the component that is passed-in. + The gain is a scale factor that the centre frequencies are multiplied by, so + values greater than 1.0 will boost the centre frequencies, values less than + 1.0 will attenuate them. + */ + void makeBandPass (const double sampleRate, + const double centreFrequency, + const double Q, + const float gainFactor) throw(); - if triggerMenuItemAutomaticallyWhenClicked is true, the menu itself will handle - detection of a mouse-click on your component, and use that to trigger the - menu ID specified in itemResultId. If this is false, the menu item can't - be triggered, so itemResultId is not used. + /** Clears the filter's coefficients so that it becomes inactive. + */ + void makeInactive() throw(); - @see PopupMenuCustomComponent + /** Makes this filter duplicate the set-up of another one. */ - void addCustomItem (const int itemResultId, - Component* customComponent, - int idealWidth, int idealHeight, - const bool triggerMenuItemAutomaticallyWhenClicked) throw(); + void copyCoefficientsFrom (const IIRFilter& other) throw(); - /** Appends a sub-menu. + juce_UseDebuggingNewOperator - If the menu that's passed in is empty, it will appear as an inactive item. - */ - void addSubMenu (const String& subMenuName, - const PopupMenu& subMenu, - const bool isActive = true, - Image* const iconToUse = 0, - const bool isTicked = false) throw(); +protected: + CriticalSection processLock; - /** Appends a separator to the menu, to help break it up into sections. + void setCoefficients (double c1, double c2, double c3, + double c4, double c5, double c6) throw(); - The menu class is smart enough not to display separators at the top or bottom - of the menu, and it will replace mutliple adjacent separators with a single - one, so your code can be quite free and easy about adding these, and it'll - always look ok. - */ - void addSeparator() throw(); + bool active; + float coefficients[6]; + float x1, x2, y1, y2; - /** Adds a non-clickable text item to the menu. + // (use the copyCoefficientsFrom() method instead of this operator) + const IIRFilter& operator= (const IIRFilter&); +}; - This is a bold-font items which can be used as a header to separate the items - into named groups. - */ - void addSectionHeader (const String& title) throw(); +#endif // __JUCE_IIRFILTER_JUCEHEADER__ +/********* End of inlined file: juce_IIRFilter.h *********/ - /** Returns the number of items that the menu currently contains. +/** + An AudioSource that performs an IIR filter on another source. +*/ +class JUCE_API IIRFilterAudioSource : public AudioSource +{ +public: - (This doesn't count separators). + /** Creates a IIRFilterAudioSource for a given input source. + + @param inputSource the input source to read from + @param deleteInputWhenDeleted if true, the input source will be deleted when + this object is deleted */ - int getNumItems() const throw(); + IIRFilterAudioSource (AudioSource* const inputSource, + const bool deleteInputWhenDeleted); - /** Returns true if the menu contains a command item that triggers the given command. */ - bool containsCommandItem (const int commandID) const throw(); + /** Destructor. */ + ~IIRFilterAudioSource(); - /** Returns true if the menu contains any items that can be used. */ - bool containsAnyActiveItems() const throw(); + /** Changes the filter to use the same parameters as the one being passed in. + */ + void setFilterParameters (const IIRFilter& newSettings); - /** Displays the menu and waits for the user to pick something. + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void releaseResources(); + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - This will display the menu modally, and return the ID of the item that the - user picks. If they click somewhere off the menu to get rid of it without - choosing anything, this will return 0. + juce_UseDebuggingNewOperator - The current location of the mouse will be used as the position to show the - menu - to explicitly set the menu's position, use showAt() instead. Depending - on where this point is on the screen, the menu will appear above, below or - to the side of the point. +private: - @param itemIdThatMustBeVisible if you set this to the ID of one of the menu items, - then when the menu first appears, it will make sure - that this item is visible. So if the menu has too many - items to fit on the screen, it will be scrolled to a - position where this item is visible. - @param minimumWidth a minimum width for the menu, in pixels. It may be wider - than this if some items are too long to fit. - @param maximumNumColumns if there are too many items to fit on-screen in a single - vertical column, the menu may be laid out as a series of - columns - this is the maximum number allowed. To use the - default value for this (probably about 7), you can pass - in zero. - @param standardItemHeight if this is non-zero, it will be used as the standard - height for menu items (apart from custom items) - @see showAt - */ - int show (const int itemIdThatMustBeVisible = 0, - const int minimumWidth = 0, - const int maximumNumColumns = 0, - const int standardItemHeight = 0); + AudioSource* const input; + const bool deleteInputWhenDeleted; + OwnedArray iirFilters; - /** Displays the menu at a specific location. + IIRFilterAudioSource (const IIRFilterAudioSource&); + const IIRFilterAudioSource& operator= (const IIRFilterAudioSource&); +}; - This is the same as show(), but uses a specific location (in global screen - co-ordinates) rather than the current mouse position. +#endif // __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_IIRFilterAudioSource.h *********/ - Note that the co-ordinates don't specify the top-left of the menu - they - indicate a point of interest, and the menu will position itself nearby to - this point, trying to keep it fully on-screen. +#endif +#ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ - @see show() - */ - int showAt (const int screenX, - const int screenY, - const int itemIdThatMustBeVisible = 0, - const int minimumWidth = 0, - const int maximumNumColumns = 0, - const int standardItemHeight = 0); +/********* Start of inlined file: juce_MixerAudioSource.h *********/ +#ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ - /** Displays the menu as if it's attached to a component such as a button. +/** + An AudioSource that mixes together the output of a set of other AudioSources. - This is similar to showAt(), but will position it next to the given component, e.g. - so that the menu's edge is aligned with that of the component. This is intended for - things like buttons that trigger a pop-up menu. + Input sources can be added and removed while the mixer is running as long as their + prepareToPlay() and releaseResources() methods are called before and after adding + them to the mixer. +*/ +class JUCE_API MixerAudioSource : public AudioSource +{ +public: + + /** Creates a MixerAudioSource. */ - int showAt (Component* componentToAttachTo, - const int itemIdThatMustBeVisible = 0, - const int minimumWidth = 0, - const int maximumNumColumns = 0, - const int standardItemHeight = 0); + MixerAudioSource(); - /** Closes any menus that are currently open. + /** Destructor. */ + ~MixerAudioSource(); - This might be useful if you have a situation where your window is being closed - by some means other than a user action, and you'd like to make sure that menus - aren't left hanging around. - */ - static void JUCE_CALLTYPE dismissAllActiveMenus() throw(); + /** Adds an input source to the mixer. - /** Specifies a look-and-feel for the menu and any sub-menus that it has. + If the mixer is running you'll need to make sure that the input source + is ready to play by calling its prepareToPlay() method before adding it. + If the mixer is stopped, then its input sources will be automatically + prepared when the mixer's prepareToPlay() method is called. - This can be called before show() if you need a customised menu. Be careful - not to delete the LookAndFeel object before the menu has been deleted. + @param newInput the source to add to the mixer + @param deleteWhenRemoved if true, then this source will be deleted when + the mixer is deleted or when removeAllInputs() is + called (unless the source is previously removed + with the removeInputSource method) */ - void setLookAndFeel (LookAndFeel* const newLookAndFeel) throw(); + void addInputSource (AudioSource* newInput, + const bool deleteWhenRemoved); - /** A set of colour IDs to use to change the colour of various aspects of the menu. + /** Removes an input source. - These constants can be used either via the LookAndFeel::setColour() - method for the look and feel that is set for this menu with setLookAndFeel() + If the mixer is running, this will remove the source but not call its + releaseResources() method, so the caller might want to do this manually. - @see setLookAndFeel, LookAndFeel::setColour, LookAndFeel::findColour + @param input the source to remove + @param deleteSource whether to delete this source after it's been removed */ - enum ColourIds - { - backgroundColourId = 0x1000700, /**< The colour to fill the menu's background with. */ - textColourId = 0x1000600, /**< The colour for normal menu item text, (unless the - colour is specified when the item is added). */ - headerTextColourId = 0x1000601, /**< The colour for section header item text (see the - addSectionHeader() method). */ - highlightedBackgroundColourId = 0x1000900, /**< The colour to fill the background of the currently - highlighted menu item. */ - highlightedTextColourId = 0x1000800, /**< The colour to use for the text of the currently - highlighted item. */ - }; + void removeInputSource (AudioSource* input, + const bool deleteSource); - /** - Allows you to iterate through the items in a pop-up menu, and examine - their properties. + /** Removes all the input sources. - To use this, just create one and repeatedly call its next() method. When this - returns true, all the member variables of the iterator are filled-out with - information describing the menu item. When it returns false, the end of the - list has been reached. + If the mixer is running, this will remove the sources but not call their + releaseResources() method, so the caller might want to do this manually. + + Any sources which were added with the deleteWhenRemoved flag set will be + deleted by this method. */ - class JUCE_API MenuItemIterator - { - public: + void removeAllInputs(); - /** Creates an iterator that will scan through the items in the specified - menu. + /** Implementation of the AudioSource method. - Be careful not to add any items to a menu while it is being iterated, - or things could get out of step. - */ - MenuItemIterator (const PopupMenu& menu) throw(); + This will call prepareToPlay() on all its input sources. + */ + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - /** Destructor. */ - ~MenuItemIterator() throw(); + /** Implementation of the AudioSource method. - /** Returns true if there is another item, and sets up all this object's - member variables to reflect that item's properties. - */ - bool next() throw(); + This will call releaseResources() on all its input sources. + */ + void releaseResources(); - String itemName; - const PopupMenu* subMenu; - int itemId; - bool isSeparator; - bool isTicked; - bool isEnabled; - bool isCustomComponent; - bool isSectionHeader; - const Colour* customColour; - const Image* customImage; - ApplicationCommandManager* commandManager; + /** Implementation of the AudioSource method. */ + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - juce_UseDebuggingNewOperator + juce_UseDebuggingNewOperator - private: - const PopupMenu& menu; - int index; +private: - MenuItemIterator (const MenuItemIterator&); - const MenuItemIterator& operator= (const MenuItemIterator&); - }; + VoidArray inputs; + BitArray inputsToDelete; + CriticalSection lock; + AudioSampleBuffer tempBuffer; + double currentSampleRate; + int bufferSizeExpected; - juce_UseDebuggingNewOperator + MixerAudioSource (const MixerAudioSource&); + const MixerAudioSource& operator= (const MixerAudioSource&); +}; -private: - friend class PopupMenuWindow; - friend class MenuItemIterator; - VoidArray items; - LookAndFeel* lookAndFeel; - bool separatorPending; +#endif // __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_MixerAudioSource.h *********/ - void addSeparatorIfPending(); +#endif +#ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ - int showMenu (const int x, const int y, const int w, const int h, - const int itemIdThatMustBeVisible, - const int minimumWidth, - const int maximumNumColumns, - const int standardItemHeight, - const bool alignToRectangle, - Component* const componentAttachedTo) throw(); +#endif +#ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ - friend class MenuBarComponent; - Component* createMenuComponent (const int x, const int y, const int w, const int h, - const int itemIdThatMustBeVisible, - const int minimumWidth, - const int maximumNumColumns, - const int standardItemHeight, - const bool alignToRectangle, - Component* menuBarComponent, - ApplicationCommandManager** managerOfChosenCommand, - Component* const componentAttachedTo) throw(); -}; +#endif +#ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ -#endif // __JUCE_POPUPMENU_JUCEHEADER__ -/********* End of inlined file: juce_PopupMenu.h *********/ +/********* Start of inlined file: juce_ToneGeneratorAudioSource.h *********/ +#ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ +#define __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ /** - Manages a list of plugin types. - - This can be easily edited, saved and loaded, and used to create instances of - the plugin types in it. + A simple AudioSource that generates a sine wave. - @see PluginListComponent */ -class JUCE_API KnownPluginList : public ChangeBroadcaster +class JUCE_API ToneGeneratorAudioSource : public AudioSource { public: - /** Creates an empty list. - */ - KnownPluginList(); + /** Creates a ToneGeneratorAudioSource. */ + ToneGeneratorAudioSource(); /** Destructor. */ - ~KnownPluginList(); - - /** Clears the list. */ - void clear(); + ~ToneGeneratorAudioSource(); - /** Returns the number of types currently in the list. - @see getType - */ - int getNumTypes() const throw() { return types.size(); } + /** Sets the signal's amplitude. */ + void setAmplitude (const float newAmplitude); - /** Returns one of the types. - @see getNumTypes - */ - PluginDescription* getType (const int index) const throw() { return types [index]; } + /** Sets the signal's frequency. */ + void setFrequency (const double newFrequencyHz); - /** Looks for a type in the list which comes from this file. - */ - PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); + /** Implementation of the AudioSource method. */ + void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - /** Looks for a type in the list which matches a plugin type ID. + /** Implementation of the AudioSource method. */ + void releaseResources(); - The identifierString parameter must have been created by - PluginDescription::createIdentifierString(). - */ - PluginDescription* getTypeForIdentifierString (const String& identifierString) const throw(); + /** Implementation of the AudioSource method. */ + void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); - /** Adds a type manually from its description. */ - bool addType (const PluginDescription& type); + juce_UseDebuggingNewOperator - /** Removes a type. */ - void removeType (const int index) throw(); +private: - /** Looks for all types that can be loaded from a given file, and adds them - to the list. + double frequency, sampleRate; + double currentPhase, phasePerSample; + float amplitude; - If dontRescanIfAlreadyInList is true, then the file will only be loaded and - re-tested if it's not already in the list, or if the file's modification - time has changed since the list was created. If dontRescanIfAlreadyInList is - false, the file will always be reloaded and tested. + ToneGeneratorAudioSource (const ToneGeneratorAudioSource&); + const ToneGeneratorAudioSource& operator= (const ToneGeneratorAudioSource&); +}; - Returns true if any new types were added, and all the types found in this - file (even if it was already known and hasn't been re-scanned) get returned - in the array. - */ - bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, - const bool dontRescanIfAlreadyInList, - OwnedArray & typesFound, - AudioPluginFormat& formatToUse); +#endif // __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ +/********* End of inlined file: juce_ToneGeneratorAudioSource.h *********/ - /** Returns true if the specified file is already known about and if it - hasn't been modified since our entry was created. - */ - bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); +#endif +#ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ - /** Scans and adds a bunch of files that might have been dragged-and-dropped. +/********* Start of inlined file: juce_AudioDeviceManager.h *********/ +#ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ +#define __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ - If any types are found in the files, their descriptions are returned in the array. - */ - void scanAndAddDragAndDroppedFiles (const StringArray& filenames, - OwnedArray & typesFound); +/********* Start of inlined file: juce_AudioIODeviceType.h *********/ +#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ +#define __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ - /** Sort methods used to change the order of the plugins in the list. - */ - enum SortMethod - { - defaultOrder = 0, - sortAlphabetically, - sortByCategory, - sortByManufacturer, - sortByFileSystemLocation - }; +class AudioDeviceManager; +class Component; - /** Adds all the plugin types to a popup menu so that the user can select one. +/** + Represents a type of audio driver, such as DirectSound, ASIO, CoreAudio, etc. - Depending on the sort method, it may add sub-menus for categories, - manufacturers, etc. + To get a list of available audio driver types, use the createDeviceTypes() + method. Each of the objects returned can then be used to list the available + devices of that type. E.g. + @code + OwnedArray types; + AudioIODeviceType::createDeviceTypes (types); - Use getIndexChosenByMenu() to find out the type that was chosen. - */ - void addToMenu (PopupMenu& menu, - const SortMethod sortMethod) const; + for (int i = 0; i < types.size(); ++i) + { + String typeName (types[i]->getTypeName()); // This will be things like "DirectSound", "CoreAudio", etc. - /** Converts a menu item index that has been chosen into its index in this list. + types[i]->scanForDevices(); // This must be called before getting the list of devices - Returns -1 if it's not an ID that was used. + StringArray deviceNames (types[i]->getDeviceNames()); // This will now return a list of available devices of this type - @see addToMenu - */ - int getIndexChosenByMenu (const int menuResultCode) const; + for (int j = 0; j < deviceNames.size(); ++j) + { + AudioIODevice* device = types[i]->createDevice (deviceNames [j]); - /** Sorts the list. */ - void sort (const SortMethod method); + ... + } + } + @endcode - /** Creates some XML that can be used to store the state of this list. - */ - XmlElement* createXml() const; + For an easier way of managing audio devices and their settings, have a look at the + AudioDeviceManager class. - /** Recreates the state of this list from its stored XML format. - */ - void recreateFromXml (const XmlElement& xml); + @see AudioIODevice, AudioDeviceManager +*/ +class JUCE_API AudioIODeviceType +{ +public: - juce_UseDebuggingNewOperator + /** Returns the name of this type of driver that this object manages. -private: - OwnedArray types; + This will be something like "DirectSound", "ASIO", "CoreAudio", "ALSA", etc. + */ + const String& getTypeName() const throw() { return typeName; } - KnownPluginList (const KnownPluginList&); - const KnownPluginList& operator= (const KnownPluginList&); -}; + /** Refreshes the object's cached list of known devices. -#endif // __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ -/********* End of inlined file: juce_KnownPluginList.h *********/ + This must be called at least once before calling getDeviceNames() or any of + the other device creation methods. + */ + virtual void scanForDevices() = 0; -/** - A type of AudioProcessor which plays back a graph of other AudioProcessors. + /** Returns the list of available devices of this type. - Use one of these objects if you want to wire-up a set of AudioProcessors - and play back the result. + The scanForDevices() method must have been called to create this list. - Processors can be added to the graph as "nodes" using addNode(), and once - added, you can connect any of their input or output channels to other - nodes using addConnection(). + @param wantInputNames only really used by DirectSound where devices are split up + into inputs and outputs, this indicates whether to use + the input or output name to refer to a pair of devices. + */ + virtual const StringArray getDeviceNames (const bool wantInputNames = false) const = 0; - To play back a graph through an audio device, you might want to use an - AudioProcessorPlayer object. -*/ -class JUCE_API AudioProcessorGraph : public AudioProcessor, - public AsyncUpdater -{ -public: + /** Returns the name of the default device. - /** Creates an empty graph. + This will be one of the names from the getDeviceNames() list. + + @param forInput if true, this means that a default input device should be + returned; if false, it should return the default output */ - AudioProcessorGraph(); + virtual int getDefaultDeviceIndex (const bool forInput) const = 0; - /** Destructor. + /** Returns the index of a given device in the list of device names. + If asInput is true, it shows the index in the inputs list, otherwise it + looks for it in the outputs list. + */ + virtual int getIndexOfDevice (AudioIODevice* device, const bool asInput) const = 0; - Any processor objects that have been added to the graph will also be deleted. + /** Returns true if two different devices can be used for the input and output. */ - ~AudioProcessorGraph(); + virtual bool hasSeparateInputsAndOutputs() const = 0; - /** Represents one of the nodes, or processors, in an AudioProcessorGraph. + /** Creates one of the devices of this type. - To create a node, call AudioProcessorGraph::addNode(). + The deviceName must be one of the strings returned by getDeviceNames(), and + scanForDevices() must have been called before this method is used. */ - class JUCE_API Node : public ReferenceCountedObject - { - public: - /** Destructor. - */ - ~Node(); + virtual AudioIODevice* createDevice (const String& outputDeviceName, + const String& inputDeviceName) = 0; - /** The ID number assigned to this node. + struct DeviceSetupDetails + { + AudioDeviceManager* manager; + int minNumInputChannels, maxNumInputChannels; + int minNumOutputChannels, maxNumOutputChannels; + bool useStereoPairs; + }; - This is assigned by the graph that owns it, and can't be changed. - */ - const uint32 id; + /** Destructor. */ + virtual ~AudioIODeviceType(); - /** The actual processor object that this node represents. - */ - AudioProcessor* const processor; +protected: + AudioIODeviceType (const tchar* const typeName); - /** A set of user-definable properties that are associated with this node. +private: + String typeName; - This can be used to attach values to the node for whatever purpose seems - useful. For example, you might store an x and y position if your application - is displaying the nodes on-screen. - */ - PropertySet properties; + AudioIODeviceType (const AudioIODeviceType&); + const AudioIODeviceType& operator= (const AudioIODeviceType&); +}; - /** A convenient typedef for referring to a pointer to a node object. - */ - typedef ReferenceCountedObjectPtr Ptr; +#endif // __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ +/********* End of inlined file: juce_AudioIODeviceType.h *********/ - juce_UseDebuggingNewOperator +/********* Start of inlined file: juce_MidiInput.h *********/ +#ifndef __JUCE_MIDIINPUT_JUCEHEADER__ +#define __JUCE_MIDIINPUT_JUCEHEADER__ - private: - friend class AudioProcessorGraph; +/********* Start of inlined file: juce_MidiMessage.h *********/ +#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ +#define __JUCE_MIDIMESSAGE_JUCEHEADER__ - bool isPrepared; +/** + Encapsulates a MIDI message. - Node (const uint32 id, AudioProcessor* const processor) throw(); + @see MidiMessageSequence, MidiOutput, MidiInput +*/ +class JUCE_API MidiMessage +{ +public: - void prepare (const double sampleRate, const int blockSize, AudioProcessorGraph* const graph); - void unprepare(); + /** Creates a 3-byte short midi message. - Node (const Node&); - const Node& operator= (const Node&); - }; + @param byte1 message byte 1 + @param byte2 message byte 2 + @param byte3 message byte 3 + @param timeStamp the time to give the midi message - this value doesn't + use any particular units, so will be application-specific + */ + MidiMessage (const int byte1, + const int byte2, + const int byte3, + const double timeStamp = 0) throw(); - /** Represents a connection between two channels of two nodes in an AudioProcessorGraph. + /** Creates a 2-byte short midi message. - To create a connection, use AudioProcessorGraph::addConnection(). + @param byte1 message byte 1 + @param byte2 message byte 2 + @param timeStamp the time to give the midi message - this value doesn't + use any particular units, so will be application-specific */ - struct JUCE_API Connection - { - public: - - /** The ID number of the node which is the input source for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 sourceNodeId; + MidiMessage (const int byte1, + const int byte2, + const double timeStamp = 0) throw(); - /** The index of the output channel of the source node from which this - connection takes its data. + /** Creates a 1-byte short midi message. - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the source node's midi output. Otherwise, it is the zero-based - index of an audio output channel in the source node. - */ - int sourceChannelIndex; + @param byte1 message byte 1 + @param timeStamp the time to give the midi message - this value doesn't + use any particular units, so will be application-specific + */ + MidiMessage (const int byte1, + const double timeStamp = 0) throw(); - /** The ID number of the node which is the destination for this connection. - @see AudioProcessorGraph::getNodeForId - */ - uint32 destNodeId; + /** Creates a midi message from a block of data. */ + MidiMessage (const uint8* const data, + const int dataSize, + const double timeStamp = 0) throw(); - /** The index of the input channel of the destination node to which this - connection delivers its data. + /** Reads the next midi message from some data. - If this value is the special number AudioProcessorGraph::midiChannelIndex, then - it is referring to the destination node's midi input. Otherwise, it is the zero-based - index of an audio input channel in the destination node. - */ - int destChannelIndex; + This will read as many bytes from a data stream as it needs to make a + complete message, and will return the number of bytes it used. This lets + you read a sequence of midi messages from a file or stream. - juce_UseDebuggingNewOperator + @param data the data to read from + @param size the maximum number of bytes it's allowed to read + @param numBytesUsed returns the number of bytes that were actually needed + @param lastStatusByte in a sequence of midi messages, the initial byte + can be dropped from a message if it's the same as the + first byte of the previous message, so this lets you + supply the byte to use if the first byte of the message + has in fact been dropped. + @param timeStamp the time to give the midi message - this value doesn't + use any particular units, so will be application-specific + */ + MidiMessage (const uint8* data, + int size, + int& numBytesUsed, + uint8 lastStatusByte, + double timeStamp = 0) throw(); - private: - }; + /** Creates a copy of another midi message. */ + MidiMessage (const MidiMessage& other) throw(); - /** Deletes all nodes and connections from this graph. + /** Creates a copy of another midi message, with a different timestamp. */ + MidiMessage (const MidiMessage& other, + const double newTimeStamp) throw(); - Any processor objects in the graph will be deleted. - */ - void clear(); + /** Destructor. */ + ~MidiMessage() throw(); - /** Returns the number of nodes in the graph. */ - int getNumNodes() const throw() { return nodes.size(); } + /** Copies this message from another one. */ + const MidiMessage& operator= (const MidiMessage& other) throw(); - /** Returns a pointer to one of the nodes in the graph. + /** Returns a pointer to the raw midi data. - This will return 0 if the index is out of range. - @see getNodeForId + @see getRawDataSize */ - Node* getNode (const int index) const throw() { return nodes [index]; } + uint8* getRawData() const throw() { return data; } - /** Searches the graph for a node with the given ID number and returns it. + /** Returns the number of bytes of data in the message. - If no such node was found, this returns 0. - @see getNode + @see getRawData */ - Node* getNodeForId (const uint32 nodeId) const throw(); + int getRawDataSize() const throw() { return size; } - /** Adds a node to the graph. + /** Returns the timestamp associated with this message. - This creates a new node in the graph, for the specified processor. Once you have - added a processor to the graph, the graph owns it and will delete it later when - it is no longer needed. + The exact meaning of this time and its units will vary, as messages are used in + a variety of different contexts. - The optional nodeId parameter lets you specify an ID to use for the node, but - if the value is already in use, this new node will overwrite the old one. + If you're getting the message from a midi file, this could be a time in seconds, or + a number of ticks - see MidiFile::convertTimestampTicksToSeconds(). - If this succeeds, it returns a pointer to the newly-created node. - */ - Node* addNode (AudioProcessor* const newProcessor, - uint32 nodeId = 0); + If the message is being used in a MidiBuffer, it might indicate the number of + audio samples from the start of the buffer. - /** Deletes a node within the graph which has the specified ID. + If the message was created by a MidiInput, see MidiInputCallback::handleIncomingMidiMessage() + for details of the way that it initialises this value. - This will also delete any connections that are attached to this node. + @see setTimeStamp, addToTimeStamp */ - bool removeNode (const uint32 nodeId); - - /** Returns the number of connections in the graph. */ - int getNumConnections() const throw() { return connections.size(); } + double getTimeStamp() const throw() { return timeStamp; } - /** Returns a pointer to one of the connections in the graph. */ - const Connection* getConnection (const int index) const throw() { return connections [index]; } + /** Changes the message's associated timestamp. - /** Searches for a connection between some specified channels. + The units for the timestamp will be application-specific - see the notes for getTimeStamp(). - If no such connection is found, this returns 0. + @see addToTimeStamp, getTimeStamp */ - const Connection* getConnectionBetween (const uint32 sourceNodeId, - const int sourceChannelIndex, - const uint32 destNodeId, - const int destChannelIndex) const throw(); + void setTimeStamp (const double newTimestamp) throw() { timeStamp = newTimestamp; } - /** Returns true if there is a connection between any of the channels of - two specified nodes. - */ - bool isConnected (const uint32 possibleSourceNodeId, - const uint32 possibleDestNodeId) const throw(); + /** Adds a value to the message's timestamp. - /** Returns true if it would be legal to connect the specified points. + The units for the timestamp will be application-specific. */ - bool canConnect (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex) const throw(); + void addToTimeStamp (const double delta) throw() { timeStamp += delta; } - /** Attempts to connect two specified channels of two nodes. + /** Returns the midi channel associated with the message. - If this isn't allowed (e.g. because you're trying to connect a midi channel - to an audio one or other such nonsense), then it'll return false. + @returns a value 1 to 16 if the message has a channel, or 0 if it hasn't (e.g. + if it's a sysex) + @see isForChannel, setChannel */ - bool addConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex); + int getChannel() const throw(); - /** Deletes the connection with the specified index. + /** Returns true if the message applies to the given midi channel. - Returns true if a connection was actually deleted. + @param channelNumber the channel number to look for, in the range 1 to 16 + @see getChannel, setChannel */ - void removeConnection (const int index); + bool isForChannel (const int channelNumber) const throw(); - /** Deletes any connection between two specified points. + /** Changes the message's midi channel. - Returns true if a connection was actually deleted. + This won't do anything for non-channel messages like sysexes. + + @param newChannelNumber the channel number to change it to, in the range 1 to 16 */ - bool removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, - const uint32 destNodeId, const int destChannelIndex); + void setChannel (const int newChannelNumber) throw(); - /** Removes all connections from the specified node. + /** Returns true if this is a system-exclusive message. */ - bool disconnectNode (const uint32 nodeId); + bool isSysEx() const throw(); - /** Performs a sanity checks of all the connections. + /** Returns a pointer to the sysex data inside the message. - This might be useful if some of the processors are doing things like changing - their channel counts, which could render some connections obsolete. + If this event isn't a sysex event, it'll return 0. + + @see getSysExDataSize */ - bool removeIllegalConnections(); + const uint8* getSysExData() const throw(); - /** A special number that represents the midi channel of a node. + /** Returns the size of the sysex data. - This is used as a channel index value if you want to refer to the midi input - or output instead of an audio channel. + This value excludes the 0xf0 header byte and the 0xf7 at the end. + + @see getSysExData */ - static const int midiChannelIndex; + int getSysExDataSize() const throw(); - /** A special type of AudioProcessor that can live inside an AudioProcessorGraph - in order to use the audio that comes into and out of the graph itself. + /** Returns true if this message is a 'key-down' event. - If you create an AudioGraphIOProcessor in "input" mode, it will act as a - node in the graph which delivers the audio that is coming into the parent - graph. This allows you to stream the data to other nodes and process the - incoming audio. + @param returnTrueForVelocity0 if true, then if this event is a note-on with + velocity 0, it will still be considered to be a note-on and the + method will return true. If returnTrueForVelocity0 is false, then + if this is a note-on event with velocity 0, it'll be regarded as + a note-off, and the method will return false - Likewise, one of these in "output" mode can be sent data which it will add to - the sum of data being sent to the graph's output. + @see isNoteOff, getNoteNumber, getVelocity, noteOn + */ + bool isNoteOn (const bool returnTrueForVelocity0 = false) const throw(); - @see AudioProcessorGraph + /** Creates a key-down message (using a floating-point velocity). + + @param channel the midi channel, in the range 1 to 16 + @param noteNumber the key number, 0 to 127 + @param velocity in the range 0 to 1.0 + @see isNoteOn */ - class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance - { - public: - /** Specifies the mode in which this processor will operate. - */ - enum IODeviceType - { - audioInputNode, /**< In this mode, the processor has output channels - representing all the audio input channels that are - coming into its parent audio graph. */ - audioOutputNode, /**< In this mode, the processor has input channels - representing all the audio output channels that are - going out of its parent audio graph. */ - midiInputNode, /**< In this mode, the processor has a midi output which - delivers the same midi data that is arriving at its - parent graph. */ - midiOutputNode /**< In this mode, the processor has a midi input and - any data sent to it will be passed out of the parent - graph. */ - }; + static const MidiMessage noteOn (const int channel, + const int noteNumber, + const float velocity) throw(); - /** Returns the mode of this processor. */ - IODeviceType getType() const throw() { return type; } + /** Creates a key-down message (using an integer velocity). - /** Returns the parent graph to which this processor belongs, or 0 if it - hasn't yet been added to one. */ - AudioProcessorGraph* getParentGraph() const throw() { return graph; } + @param channel the midi channel, in the range 1 to 16 + @param noteNumber the key number, 0 to 127 + @param velocity in the range 0 to 127 + @see isNoteOn + */ + static const MidiMessage noteOn (const int channel, + const int noteNumber, + const uint8 velocity) throw(); - /** True if this is an audio or midi input. */ - bool isInput() const throw(); - /** True if this is an audio or midi output. */ - bool isOutput() const throw(); + /** Returns true if this message is a 'key-up' event. - AudioGraphIOProcessor (const IODeviceType type); - ~AudioGraphIOProcessor(); + If returnTrueForNoteOnVelocity0 is true, then his will also return true + for a note-on event with a velocity of 0. - const String getName() const; - void fillInPluginDescription (PluginDescription& d) const; + @see isNoteOn, getNoteNumber, getVelocity, noteOff + */ + bool isNoteOff (const bool returnTrueForNoteOnVelocity0 = true) const throw(); - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + /** Creates a key-up message. - const String getInputChannelName (const int channelIndex) const; - const String getOutputChannelName (const int channelIndex) const; - bool isInputChannelStereoPair (int index) const; - bool isOutputChannelStereoPair (int index) const; - bool acceptsMidi() const; - bool producesMidi() const; + @param channel the midi channel, in the range 1 to 16 + @param noteNumber the key number, 0 to 127 + @see isNoteOff + */ + static const MidiMessage noteOff (const int channel, + const int noteNumber) throw(); - AudioProcessorEditor* createEditor(); + /** Returns true if this message is a 'key-down' or 'key-up' event. - int getNumParameters(); - const String getParameterName (int); - float getParameter (int); - const String getParameterText (int); - void setParameter (int, float); + @see isNoteOn, isNoteOff + */ + bool isNoteOnOrOff() const throw(); - int getNumPrograms(); - int getCurrentProgram(); - void setCurrentProgram (int); - const String getProgramName (int); - void changeProgramName (int, const String&); + /** Returns the midi note number for note-on and note-off messages. - void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); + If the message isn't a note-on or off, the value returned will be + meaningless. - /** @internal */ - void setParentGraph (AudioProcessorGraph* const graph) throw(); + @see isNoteOff, getMidiNoteName, getMidiNoteInHertz, setNoteNumber + */ + int getNoteNumber() const throw(); - juce_UseDebuggingNewOperator + /** Changes the midi note number of a note-on or note-off message. - private: - const IODeviceType type; - AudioProcessorGraph* graph; + If the message isn't a note on or off, this will do nothing. + */ + void setNoteNumber (const int newNoteNumber) throw(); - AudioGraphIOProcessor (const AudioGraphIOProcessor&); - const AudioGraphIOProcessor& operator= (const AudioGraphIOProcessor&); - }; + /** Returns the velocity of a note-on or note-off message. - // AudioProcessor methods: + The value returned will be in the range 0 to 127. - const String getName() const; + If the message isn't a note-on or off event, it will return 0. - void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); - void releaseResources(); - void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + @see getFloatVelocity + */ + uint8 getVelocity() const throw(); - const String getInputChannelName (const int channelIndex) const; - const String getOutputChannelName (const int channelIndex) const; - bool isInputChannelStereoPair (int index) const; - bool isOutputChannelStereoPair (int index) const; + /** Returns the velocity of a note-on or note-off message. - bool acceptsMidi() const; - bool producesMidi() const; + The value returned will be in the range 0 to 1.0 - AudioProcessorEditor* createEditor() { return 0; } + If the message isn't a note-on or off event, it will return 0. - int getNumParameters() { return 0; } - const String getParameterName (int) { return String::empty; } - float getParameter (int) { return 0; } - const String getParameterText (int) { return String::empty; } - void setParameter (int, float) { } + @see getVelocity, setVelocity + */ + float getFloatVelocity() const throw(); - int getNumPrograms() { return 0; } - int getCurrentProgram() { return 0; } - void setCurrentProgram (int) { } - const String getProgramName (int) { return String::empty; } - void changeProgramName (int, const String&) { } + /** Changes the velocity of a note-on or note-off message. - void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); - void setStateInformation (const void* data, int sizeInBytes); + If the message isn't a note on or off, this will do nothing. - /** @internal */ - void handleAsyncUpdate(); + @param newVelocity the new velocity, in the range 0 to 1.0 + @see getFloatVelocity, multiplyVelocity + */ + void setVelocity (const float newVelocity) throw(); - juce_UseDebuggingNewOperator + /** Multiplies the velocity of a note-on or note-off message by a given amount. -private: - ReferenceCountedArray nodes; - OwnedArray connections; - int lastNodeId; - AudioSampleBuffer renderingBuffers; - OwnedArray midiBuffers; + If the message isn't a note on or off, this will do nothing. - CriticalSection renderLock; - VoidArray renderingOps; + @param scaleFactor the value by which to multiply the velocity + @see setVelocity + */ + void multiplyVelocity (const float scaleFactor) throw(); - friend class AudioGraphIOProcessor; - AudioSampleBuffer* currentAudioInputBuffer; - AudioSampleBuffer currentAudioOutputBuffer; - MidiBuffer* currentMidiInputBuffer; - MidiBuffer currentMidiOutputBuffer; + /** Returns true if the message is a program (patch) change message. - void clearRenderingSequence(); - void buildRenderingSequence(); + @see getProgramChangeNumber, getGMInstrumentName + */ + bool isProgramChange() const throw(); - bool isAnInputTo (const uint32 possibleInputId, - const uint32 possibleDestinationId, - const int recursionCheck) const throw(); + /** Returns the new program number of a program change message. - AudioProcessorGraph (const AudioProcessorGraph&); - const AudioProcessorGraph& operator= (const AudioProcessorGraph&); -}; + If the message isn't a program change, the value returned will be + nonsense. -#endif // __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ -/********* End of inlined file: juce_AudioProcessorGraph.h *********/ + @see isProgramChange, getGMInstrumentName + */ + int getProgramChangeNumber() const throw(); -#endif -#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ + /** Creates a program-change message. -#endif -#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ + @param channel the midi channel, in the range 1 to 16 + @param programNumber the midi program number, 0 to 127 + @see isProgramChange, getGMInstrumentName + */ + static const MidiMessage programChange (const int channel, + const int programNumber) throw(); -/********* Start of inlined file: juce_AudioProcessorPlayer.h *********/ -#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ -#define __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ + /** Returns true if the message is a pitch-wheel move. -/********* Start of inlined file: juce_AudioIODevice.h *********/ -#ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__ -#define __JUCE_AUDIOIODEVICE_JUCEHEADER__ + @see getPitchWheelValue, pitchWheel + */ + bool isPitchWheel() const throw(); -class AudioIODevice; + /** Returns the pitch wheel position from a pitch-wheel move message. -/** - One of these is passed to an AudioIODevice object to stream the audio data - in and out. + The value returned is a 14-bit number from 0 to 0x3fff, indicating the wheel position. + If called for messages which aren't pitch wheel events, the number returned will be + nonsense. - The AudioIODevice will repeatedly call this class's audioDeviceIOCallback() - method on its own high-priority audio thread, when it needs to send or receive - the next block of data. + @see isPitchWheel + */ + int getPitchWheelValue() const throw(); - @see AudioIODevice, AudioDeviceManager -*/ -class JUCE_API AudioIODeviceCallback -{ -public: - /** Destructor. */ - virtual ~AudioIODeviceCallback() {} + /** Creates a pitch-wheel move message. - /** Processes a block of incoming and outgoing audio data. + @param channel the midi channel, in the range 1 to 16 + @param position the wheel position, in the range 0 to 16383 + @see isPitchWheel + */ + static const MidiMessage pitchWheel (const int channel, + const int position) throw(); - The subclass's implementation should use the incoming audio for whatever - purposes it needs to, and must fill all the output channels with the next - block of output data before returning. + /** Returns true if the message is an aftertouch event. - The channel data is arranged with the same array indices as the channel name - array returned by AudioIODevice::getOutputChannelNames(), but those channels - that aren't specified in AudioIODevice::open() will have a null pointer for their - associated channel, so remember to check for this. + For aftertouch events, use the getNoteNumber() method to find out the key + that it applies to, and getAftertouchValue() to find out the amount. Use + getChannel() to find out the channel. - @param inputChannelData a set of arrays containing the audio data for each - incoming channel - this data is valid until the function - returns. There will be one channel of data for each input - channel that was enabled when the audio device was opened - (see AudioIODevice::open()) - @param numInputChannels the number of pointers to channel data in the - inputChannelData array. - @param outputChannelData a set of arrays which need to be filled with the data - that should be sent to each outgoing channel of the device. - There will be one channel of data for each output channel - that was enabled when the audio device was opened (see - AudioIODevice::open()) - The initial contents of the array is undefined, so the - callback function must fill all the channels with zeros if - its output is silence. Failing to do this could cause quite - an unpleasant noise! - @param numOutputChannels the number of pointers to channel data in the - outputChannelData array. - @param numSamples the number of samples in each channel of the input and - output arrays. The number of samples will depend on the - audio device's buffer size and will usually remain constant, - although this isn't guaranteed, so make sure your code can - cope with reasonable changes in the buffer size from one - callback to the next. + @see getAftertouchValue, getNoteNumber */ - virtual void audioDeviceIOCallback (const float** inputChannelData, - int numInputChannels, - float** outputChannelData, - int numOutputChannels, - int numSamples) = 0; - - /** Called to indicate that the device is about to start calling back. + bool isAftertouch() const throw(); - This will be called just before the audio callbacks begin, either when this - callback has just been added to an audio device, or after the device has been - restarted because of a sample-rate or block-size change. + /** Returns the amount of aftertouch from an aftertouch messages. - You can use this opportunity to find out the sample rate and block size - that the device is going to use by calling the AudioIODevice::getCurrentSampleRate() - and AudioIODevice::getCurrentBufferSizeSamples() on the supplied pointer. + The value returned is in the range 0 to 127, and will be nonsense for messages + other than aftertouch messages. - @param device the audio IO device that will be used to drive the callback. - Note that if you're going to store this this pointer, it is - only valid until the next time that audioDeviceStopped is called. + @see isAftertouch */ - virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; + int getAfterTouchValue() const throw(); - /** Called to indicate that the device has stopped. - */ - virtual void audioDeviceStopped() = 0; -}; + /** Creates an aftertouch message. -/** - Base class for an audio device with synchronised input and output channels. + @param channel the midi channel, in the range 1 to 16 + @param noteNumber the key number, 0 to 127 + @param aftertouchAmount the amount of aftertouch, 0 to 127 + @see isAftertouch + */ + static const MidiMessage aftertouchChange (const int channel, + const int noteNumber, + const int aftertouchAmount) throw(); - Subclasses of this are used to implement different protocols such as DirectSound, - ASIO, CoreAudio, etc. + /** Returns true if the message is a channel-pressure change event. - To create one of these, you'll need to use the AudioIODeviceType class - see the - documentation for that class for more info. + This is like aftertouch, but common to the whole channel rather than a specific + note. Use getChannelPressureValue() to find out the pressure, and getChannel() + to find out the channel. - For an easier way of managing audio devices and their settings, have a look at the - AudioDeviceManager class. + @see channelPressureChange + */ + bool isChannelPressure() const throw(); - @see AudioIODeviceType, AudioDeviceManager -*/ -class JUCE_API AudioIODevice -{ -public: - /** Destructor. */ - virtual ~AudioIODevice(); + /** Returns the pressure from a channel pressure change message. - /** Returns the device's name, (as set in the constructor). */ - const String& getName() const throw() { return name; } + @returns the pressure, in the range 0 to 127 + @see isChannelPressure, channelPressureChange + */ + int getChannelPressureValue() const throw(); - /** Returns the type of the device. + /** Creates a channel-pressure change event. - E.g. "CoreAudio", "ASIO", etc. - this comes from the AudioIODeviceType that created it. + @param channel the midi channel: 1 to 16 + @param pressure the pressure, 0 to 127 + @see isChannelPressure */ - const String& getTypeName() const throw() { return typeName; } + static const MidiMessage channelPressureChange (const int channel, + const int pressure) throw(); - /** Returns the names of all the available output channels on this device. - To find out which of these are currently in use, call getActiveOutputChannels(). - */ - virtual const StringArray getOutputChannelNames() = 0; + /** Returns true if this is a midi controller message. - /** Returns the names of all the available input channels on this device. - To find out which of these are currently in use, call getActiveInputChannels(). + @see getControllerNumber, getControllerValue, controllerEvent */ - virtual const StringArray getInputChannelNames() = 0; + bool isController() const throw(); - /** Returns the number of sample-rates this device supports. + /** Returns the controller number of a controller message. - To find out which rates are available on this device, use this method to - find out how many there are, and getSampleRate() to get the rates. + The name of the controller can be looked up using the getControllerName() method. - @see getSampleRate + Note that the value returned is invalid for messages that aren't controller changes. + + @see isController, getControllerName, getControllerValue */ - virtual int getNumSampleRates() = 0; + int getControllerNumber() const throw(); - /** Returns one of the sample-rates this device supports. + /** Returns the controller value from a controller message. - To find out which rates are available on this device, use getNumSampleRates() to - find out how many there are, and getSampleRate() to get the individual rates. + A value 0 to 127 is returned to indicate the new controller position. - The sample rate is set by the open() method. + Note that the value returned is invalid for messages that aren't controller changes. - (Note that for DirectSound some rates might not work, depending on combinations - of i/o channels that are being opened). + @see isController, getControllerNumber + */ + int getControllerValue() const throw(); - @see getNumSampleRates + /** Creates a controller message. + + @param channel the midi channel, in the range 1 to 16 + @param controllerType the type of controller + @param value the controller value + @see isController */ - virtual double getSampleRate (int index) = 0; + static const MidiMessage controllerEvent (const int channel, + const int controllerType, + const int value) throw(); - /** Returns the number of sizes of buffer that are available. + /** Checks whether this message is an all-notes-off message. - @see getBufferSizeSamples, getDefaultBufferSize + @see allNotesOff */ - virtual int getNumBufferSizesAvailable() = 0; + bool isAllNotesOff() const throw(); - /** Returns one of the possible buffer-sizes. + /** Checks whether this message is an all-sound-off message. - @param index the index of the buffer-size to use, from 0 to getNumBufferSizesAvailable() - 1 - @returns a number of samples - @see getNumBufferSizesAvailable, getDefaultBufferSize + @see allSoundOff */ - virtual int getBufferSizeSamples (int index) = 0; + bool isAllSoundOff() const throw(); - /** Returns the default buffer-size to use. + /** Creates an all-notes-off message. - @returns a number of samples - @see getNumBufferSizesAvailable, getBufferSizeSamples + @param channel the midi channel, in the range 1 to 16 + @see isAllNotesOff */ - virtual int getDefaultBufferSize() = 0; + static const MidiMessage allNotesOff (const int channel) throw(); - /** Tries to open the device ready to play. + /** Creates an all-sound-off message. - @param inputChannels a BitArray in which a set bit indicates that the corresponding - input channel should be enabled - @param outputChannels a BitArray in which a set bit indicates that the corresponding - output channel should be enabled - @param sampleRate the sample rate to try to use - to find out which rates are - available, see getNumSampleRates() and getSampleRate() - @param bufferSizeSamples the size of i/o buffer to use - to find out the available buffer - sizes, see getNumBufferSizesAvailable() and getBufferSizeSamples() - @returns an error description if there's a problem, or an empty string if it succeeds in - opening the device - @see close + @param channel the midi channel, in the range 1 to 16 + @see isAllSoundOff */ - virtual const String open (const BitArray& inputChannels, - const BitArray& outputChannels, - double sampleRate, - int bufferSizeSamples) = 0; + static const MidiMessage allSoundOff (const int channel) throw(); - /** Closes and releases the device if it's open. */ - virtual void close() = 0; + /** Creates an all-controllers-off message. - /** Returns true if the device is still open. + @param channel the midi channel, in the range 1 to 16 + */ + static const MidiMessage allControllersOff (const int channel) throw(); - A device might spontaneously close itself if something goes wrong, so this checks if - it's still open. + /** Returns true if this event is a meta-event. + + Meta-events are things like tempo changes, track names, etc. + + @see getMetaEventType, isTrackMetaEvent, isEndOfTrackMetaEvent, + isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, + isKeySignatureMetaEvent, isMidiChannelMetaEvent */ - virtual bool isOpen() = 0; + bool isMetaEvent() const throw(); - /** Starts the device actually playing. + /** Returns a meta-event's type number. - This must be called after the device has been opened. + If the message isn't a meta-event, this will return -1. - @param callback the callback to use for streaming the data. - @see AudioIODeviceCallback, open + @see isMetaEvent, isTrackMetaEvent, isEndOfTrackMetaEvent, + isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, + isKeySignatureMetaEvent, isMidiChannelMetaEvent */ - virtual void start (AudioIODeviceCallback* callback) = 0; + int getMetaEventType() const throw(); - /** Stops the device playing. + /** Returns a pointer to the data in a meta-event. - Once a device has been started, this will stop it. Any pending calls to the - callback class will be flushed before this method returns. + @see isMetaEvent, getMetaEventLength */ - virtual void stop() = 0; + const uint8* getMetaEventData() const throw(); - /** Returns true if the device is still calling back. + /** Returns the length of the data for a meta-event. - The device might mysteriously stop, so this checks whether it's - still playing. + @see isMetaEvent, getMetaEventData */ - virtual bool isPlaying() = 0; + int getMetaEventLength() const throw(); - /** Returns the last error that happened if anything went wrong. */ - virtual const String getLastError() = 0; + /** Returns true if this is a 'track' meta-event. */ + bool isTrackMetaEvent() const throw(); - /** Returns the buffer size that the device is currently using. + /** Returns true if this is an 'end-of-track' meta-event. */ + bool isEndOfTrackMetaEvent() const throw(); - If the device isn't actually open, this value doesn't really mean much. + /** Creates an end-of-track meta-event. + + @see isEndOfTrackMetaEvent */ - virtual int getCurrentBufferSizeSamples() = 0; + static const MidiMessage endOfTrack() throw(); - /** Returns the sample rate that the device is currently using. + /** Returns true if this is an 'track name' meta-event. - If the device isn't actually open, this value doesn't really mean much. + You can use the getTextFromTextMetaEvent() method to get the track's name. */ - virtual double getCurrentSampleRate() = 0; + bool isTrackNameEvent() const throw(); - /** Returns the device's current physical bit-depth. + /** Returns true if this is a 'text' meta-event. - If the device isn't actually open, this value doesn't really mean much. + @see getTextFromTextMetaEvent */ - virtual int getCurrentBitDepth() = 0; + bool isTextMetaEvent() const throw(); - /** Returns a mask showing which of the available output channels are currently - enabled. - @see getOutputChannelNames + /** Returns the text from a text meta-event. + + @see isTextMetaEvent */ - virtual const BitArray getActiveOutputChannels() const = 0; + const String getTextFromTextMetaEvent() const throw(); - /** Returns a mask showing which of the available input channels are currently - enabled. - @see getInputChannelNames + /** Returns true if this is a 'tempo' meta-event. + + @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote */ - virtual const BitArray getActiveInputChannels() const = 0; + bool isTempoMetaEvent() const throw(); - /** Returns the device's output latency. + /** Returns the tick length from a tempo meta-event. - This is the delay in samples between a callback getting a block of data, and - that data actually getting played. + @param timeFormat the 16-bit time format value from the midi file's header. + @returns the tick length (in seconds). + @see isTempoMetaEvent */ - virtual int getOutputLatencyInSamples() = 0; + double getTempoMetaEventTickLength (const short timeFormat) const throw(); - /** Returns the device's input latency. + /** Calculates the seconds-per-quarter-note from a tempo meta-event. - This is the delay in samples between some audio actually arriving at the soundcard, - and the callback getting passed this block of data. + @see isTempoMetaEvent, getTempoMetaEventTickLength */ - virtual int getInputLatencyInSamples() = 0; + double getTempoSecondsPerQuarterNote() const throw(); - /** True if this device can show a pop-up control panel for editing its settings. + /** Creates a tempo meta-event. - This is generally just true of ASIO devices. If true, you can call showControlPanel() - to display it. + @see isTempoMetaEvent */ - virtual bool hasControlPanel() const; + static const MidiMessage tempoMetaEvent (const int microsecondsPerQuarterNote) throw(); - /** Shows a device-specific control panel if there is one. + /** Returns true if this is a 'time-signature' meta-event. - This should only be called for devices which return true from hasControlPanel(). + @see getTimeSignatureInfo */ - virtual bool showControlPanel(); + bool isTimeSignatureMetaEvent() const throw(); -protected: - /** Creates a device, setting its name and type member variables. */ - AudioIODevice (const String& deviceName, - const String& typeName); + /** Returns the time-signature values from a time-signature meta-event. - /** @internal */ - String name, typeName; -}; + @see isTimeSignatureMetaEvent + */ + void getTimeSignatureInfo (int& numerator, + int& denominator) const throw(); -#endif // __JUCE_AUDIOIODEVICE_JUCEHEADER__ -/********* End of inlined file: juce_AudioIODevice.h *********/ + /** Creates a time-signature meta-event. -/** - An AudioIODeviceCallback object which streams audio through an AudioProcessor. + @see isTimeSignatureMetaEvent + */ + static const MidiMessage timeSignatureMetaEvent (const int numerator, + const int denominator) throw(); - To use one of these, just make it the callback used by your AudioIODevice, and - give it a processor to use by calling setProcessor(). + /** Returns true if this is a 'key-signature' meta-event. - It's also a MidiInputCallback, so you can connect it to both an audio and midi - input to send both streams through the processor. + @see getKeySignatureNumberOfSharpsOrFlats + */ + bool isKeySignatureMetaEvent() const throw(); - @see AudioProcessor, AudioProcessorGraph -*/ -class JUCE_API AudioProcessorPlayer : public AudioIODeviceCallback, - public MidiInputCallback -{ -public: + /** Returns the key from a key-signature meta-event. - /** + @see isKeySignatureMetaEvent */ - AudioProcessorPlayer(); + int getKeySignatureNumberOfSharpsOrFlats() const throw(); - /** Destructor. */ - virtual ~AudioProcessorPlayer(); + /** Returns true if this is a 'channel' meta-event. - /** Sets the processor that should be played. + A channel meta-event specifies the midi channel that should be used + for subsequent meta-events. - The processor that is passed in will not be deleted or owned by this object. - To stop anything playing, pass in 0 to this method. + @see getMidiChannelMetaEventChannel */ - void setProcessor (AudioProcessor* const processorToPlay); + bool isMidiChannelMetaEvent() const throw(); - /** Returns the current audio processor that is being played. - */ - AudioProcessor* getCurrentProcessor() const throw() { return processor; } + /** Returns the channel number from a channel meta-event. - /** Returns a midi message collector that you can pass midi messages to if you - want them to be injected into the midi stream that is being sent to the - processor. + @returns the channel, in the range 1 to 16. + @see isMidiChannelMetaEvent */ - MidiMessageCollector& getMidiMessageCollector() throw() { return messageCollector; } + int getMidiChannelMetaEventChannel() const throw(); - /** @internal */ - void audioDeviceIOCallback (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples); - /** @internal */ - void audioDeviceAboutToStart (AudioIODevice* device); - /** @internal */ - void audioDeviceStopped(); - /** @internal */ - void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); + /** Creates a midi channel meta-event. - juce_UseDebuggingNewOperator + @param channel the midi channel, in the range 1 to 16 + @see isMidiChannelMetaEvent + */ + static const MidiMessage midiChannelMetaEvent (const int channel) throw(); -private: - AudioProcessor* processor; - CriticalSection lock; - double sampleRate; - int blockSize; - bool isPrepared; + /** Returns true if this is an active-sense message. */ + bool isActiveSense() const throw(); - int numInputChans, numOutputChans; - float* channels [128]; - AudioSampleBuffer tempBuffer; + /** Returns true if this is a midi start event. - MidiBuffer incomingMidi; - MidiMessageCollector messageCollector; + @see midiStart + */ + bool isMidiStart() const throw(); - AudioProcessorPlayer (const AudioProcessorPlayer&); - const AudioProcessorPlayer& operator= (const AudioProcessorPlayer&); -}; + /** Creates a midi start event. */ + static const MidiMessage midiStart() throw(); -#endif // __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ -/********* End of inlined file: juce_AudioProcessorPlayer.h *********/ + /** Returns true if this is a midi continue event. -#endif -#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ + @see midiContinue + */ + bool isMidiContinue() const throw(); -/********* Start of inlined file: juce_GenericAudioProcessorEditor.h *********/ -#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ -#define __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ + /** Creates a midi continue event. */ + static const MidiMessage midiContinue() throw(); -/********* Start of inlined file: juce_PropertyPanel.h *********/ -#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ -#define __JUCE_PROPERTYPANEL_JUCEHEADER__ + /** Returns true if this is a midi stop event. -/********* Start of inlined file: juce_PropertyComponent.h *********/ -#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ + @see midiStop + */ + bool isMidiStop() const throw(); -class EditableProperty; + /** Creates a midi stop event. */ + static const MidiMessage midiStop() throw(); -/********* Start of inlined file: juce_TooltipClient.h *********/ -#ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ -#define __JUCE_TOOLTIPCLIENT_JUCEHEADER__ + /** Returns true if this is a midi clock event. -/** - Components that want to use pop-up tooltips should implement this interface. + @see midiClock, songPositionPointer + */ + bool isMidiClock() const throw(); - A TooltipWindow will wait for the mouse to hover over a component that - implements the TooltipClient interface, and when it finds one, it will display - the tooltip returned by its getTooltip() method. + /** Creates a midi clock event. */ + static const MidiMessage midiClock() throw(); - @see TooltipWindow, SettableTooltipClient -*/ -class JUCE_API TooltipClient -{ -public: - /** Destructor. */ - virtual ~TooltipClient() {} + /** Returns true if this is a song-position-pointer message. - /** Returns the string that this object wants to show as its tooltip. */ - virtual const String getTooltip() = 0; -}; + @see getSongPositionPointerMidiBeat, songPositionPointer + */ + bool isSongPositionPointer() const throw(); -/** - An implementation of TooltipClient that stores the tooltip string and a method - for changing it. + /** Returns the midi beat-number of a song-position-pointer message. - This makes it easy to add a tooltip to a custom component, by simply adding this - as a base class and calling setTooltip(). + @see isSongPositionPointer, songPositionPointer + */ + int getSongPositionPointerMidiBeat() const throw(); - Many of the Juce widgets already use this as a base class to implement their - tooltips. + /** Creates a song-position-pointer message. - @see TooltipClient, TooltipWindow -*/ -class JUCE_API SettableTooltipClient : public TooltipClient -{ -public: + The position is a number of midi beats from the start of the song, where 1 midi + beat is 6 midi clocks, and there are 24 midi clocks in a quarter-note. So there + are 4 midi beats in a quarter-note. - /** Destructor. */ - virtual ~SettableTooltipClient() {} + @see isSongPositionPointer, getSongPositionPointerMidiBeat + */ + static const MidiMessage songPositionPointer (const int positionInMidiBeats) throw(); - virtual void setTooltip (const String& newTooltip) { tooltipString = newTooltip; } + /** Returns true if this is a quarter-frame midi timecode message. - virtual const String getTooltip() { return tooltipString; } + @see quarterFrame, getQuarterFrameSequenceNumber, getQuarterFrameValue + */ + bool isQuarterFrame() const throw(); - juce_UseDebuggingNewOperator + /** Returns the sequence number of a quarter-frame midi timecode message. -protected: - String tooltipString; -}; + This will be a value between 0 and 7. -#endif // __JUCE_TOOLTIPCLIENT_JUCEHEADER__ -/********* End of inlined file: juce_TooltipClient.h *********/ + @see isQuarterFrame, getQuarterFrameValue, quarterFrame + */ + int getQuarterFrameSequenceNumber() const throw(); -/** - A base class for a component that goes in a PropertyPanel and displays one of - an item's properties. + /** Returns the value from a quarter-frame message. - Subclasses of this are used to display a property in various forms, e.g. a - ChoicePropertyComponent shows its value as a combo box; a SliderPropertyComponent - shows its value as a slider; a TextPropertyComponent as a text box, etc. + This will be the lower nybble of the message's data-byte, a value + between 0 and 15 + */ + int getQuarterFrameValue() const throw(); - A subclass must implement the refresh() method which will be called to tell the - component to update itself, and is also responsible for calling this it when the - item that it refers to is changed. + /** Creates a quarter-frame MTC message. - @see PropertyPanel, TextPropertyComponent, SliderPropertyComponent, - ChoicePropertyComponent, ButtonPropertyComponent, BooleanPropertyComponent -*/ -class JUCE_API PropertyComponent : public Component, - public SettableTooltipClient -{ -public: + @param sequenceNumber a value 0 to 7 for the upper nybble of the message's data byte + @param value a value 0 to 15 for the lower nybble of the message's data byte + */ + static const MidiMessage quarterFrame (const int sequenceNumber, + const int value) throw(); - /** Creates a PropertyComponent. + /** SMPTE timecode types. - @param propertyName the name is stored as this component's name, and is - used as the name displayed next to this component in - a property panel - @param preferredHeight the height that the component should be given - some - items may need to be larger than a normal row height. - This value can also be set if a subclass changes the - preferredHeight member variable. + Used by the getFullFrameParameters() and fullFrame() methods. */ - PropertyComponent (const String& propertyName, - const int preferredHeight = 25); + enum SmpteTimecodeType + { + fps24 = 0, + fps25 = 1, + fps30drop = 2, + fps30 = 3 + }; - /** Destructor. */ - ~PropertyComponent(); + /** Returns true if this is a full-frame midi timecode message. + */ + bool isFullFrame() const throw(); - /** Returns this item's preferred height. + /** Extracts the timecode information from a full-frame midi timecode message. - This value is specified either in the constructor or by a subclass changing the - preferredHeight member variable. + You should only call this on messages where you've used isFullFrame() to + check that they're the right kind. */ - int getPreferredHeight() const throw() { return preferredHeight; } + void getFullFrameParameters (int& hours, + int& minutes, + int& seconds, + int& frames, + SmpteTimecodeType& timecodeType) const throw(); - /** Updates the property component if the item it refers to has changed. + /** Creates a full-frame MTC message. + */ + static const MidiMessage fullFrame (const int hours, + const int minutes, + const int seconds, + const int frames, + SmpteTimecodeType timecodeType); - A subclass must implement this method, and other objects may call it to - force it to refresh itself. + /** Types of MMC command. - The subclass should be economical in the amount of work is done, so for - example it should check whether it really needs to do a repaint rather than - just doing one every time this method is called, as it may be called when - the value being displayed hasn't actually changed. + @see isMidiMachineControlMessage, getMidiMachineControlCommand, midiMachineControlCommand */ - virtual void refresh() = 0; + enum MidiMachineControlCommand + { + mmc_stop = 1, + mmc_play = 2, + mmc_deferredplay = 3, + mmc_fastforward = 4, + mmc_rewind = 5, + mmc_recordStart = 6, + mmc_recordStop = 7, + mmc_pause = 9 + }; - /** The default paint method fills the background and draws a label for the - item's name. + /** Checks whether this is an MMC message. - @see LookAndFeel::drawPropertyComponentBackground(), LookAndFeel::drawPropertyComponentLabel() + If it is, you can use the getMidiMachineControlCommand() to find out its type. */ - void paint (Graphics& g); + bool isMidiMachineControlMessage() const throw(); - /** The default resize method positions any child component to the right of this - one, based on the look and feel's default label size. + /** For an MMC message, this returns its type. + + Make sure it's actually an MMC message with isMidiMachineControlMessage() before + calling this method. */ - void resized(); + MidiMachineControlCommand getMidiMachineControlCommand() const throw(); - /** By default, this just repaints the component. */ - void enablementChanged(); + /** Creates an MMC message. + */ + static const MidiMessage midiMachineControlCommand (MidiMachineControlCommand command); - juce_UseDebuggingNewOperator + /** Checks whether this is an MMC "goto" message. -protected: - /** Used by the PropertyPanel to determine how high this component needs to be. + If it is, the parameters passed-in are set to the time that the message contains. - A subclass can update this value in its constructor but shouldn't alter it later - as changes won't necessarily be picked up. + @see midiMachineControlGoto */ - int preferredHeight; -}; + bool isMidiMachineControlGoto (int& hours, + int& minutes, + int& seconds, + int& frames) const throw(); -#endif // __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_PropertyComponent.h *********/ + /** Creates an MMC "goto" message. -/********* Start of inlined file: juce_Viewport.h *********/ -#ifndef __JUCE_VIEWPORT_JUCEHEADER__ -#define __JUCE_VIEWPORT_JUCEHEADER__ + This messages tells the device to go to a specific frame. -/********* Start of inlined file: juce_ScrollBar.h *********/ -#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ -#define __JUCE_SCROLLBAR_JUCEHEADER__ + @see isMidiMachineControlGoto + */ + static const MidiMessage midiMachineControlGoto (int hours, + int minutes, + int seconds, + int frames); -/********* Start of inlined file: juce_Button.h *********/ -#ifndef __JUCE_BUTTON_JUCEHEADER__ -#define __JUCE_BUTTON_JUCEHEADER__ + /** Creates a master-volume change message. -/********* Start of inlined file: juce_TooltipWindow.h *********/ -#ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ -#define __JUCE_TOOLTIPWINDOW_JUCEHEADER__ + @param volume the volume, 0 to 1.0 + */ + static const MidiMessage masterVolume (const float volume) throw(); -/** - A window that displays a pop-up tooltip when the mouse hovers over another component. + /** Creates a system-exclusive message. - To enable tooltips in your app, just create a single instance of a TooltipWindow - object. + The data passed in is wrapped with header and tail bytes of 0xf0 and 0xf7. + */ + static const MidiMessage createSysExMessage (const uint8* sysexData, + const int dataSize) throw(); - The TooltipWindow object will then stay invisible, waiting until the mouse - hovers for the specified length of time - it will then see if it's currently - over a component which implements the TooltipClient interface, and if so, - it will make itself visible to show the tooltip in the appropriate place. + /** Reads a midi variable-length integer. - @see TooltipClient, SettableTooltipClient -*/ -class JUCE_API TooltipWindow : public Component, - private Timer -{ -public: + @param data the data to read the number from + @param numBytesUsed on return, this will be set to the number of bytes that were read + */ + static int readVariableLengthVal (const uint8* data, + int& numBytesUsed) throw(); - /** Creates a tooltip window. + /** Based on the first byte of a short midi message, this uses a lookup table + to return the message length (either 1, 2, or 3 bytes). - Make sure your app only creates one instance of this class, otherwise you'll - get multiple overlaid tooltips appearing. The window will initially be invisible - and will make itself visible when it needs to display a tip. + The value passed in must be 0x80 or higher. + */ + static int getMessageLengthFromFirstByte (const uint8 firstByte) throw(); - To change the style of tooltips, see the LookAndFeel class for its tooltip - methods. + /** Returns the name of a midi note number. - @param parentComponent if set to 0, the TooltipWindow will appear on the desktop, - otherwise the tooltip will be added to the given parent - component. - @param millisecondsBeforeTipAppears the time for which the mouse has to stay still - before a tooltip will be shown + E.g "C", "D#", etc. - @see TooltipClient, LookAndFeel::drawTooltip, LookAndFeel::getTooltipSize + @param noteNumber the midi note number, 0 to 127 + @param useSharps if true, sharpened notes are used, e.g. "C#", otherwise + they'll be flattened, e.g. "Db" + @param includeOctaveNumber if true, the octave number will be appended to the string, + e.g. "C#4" + @param octaveNumForMiddleC if an octave number is being appended, this indicates the + number that will be used for middle C's octave + + @see getMidiNoteInHertz */ - TooltipWindow (Component* parentComponent = 0, - const int millisecondsBeforeTipAppears = 700); + static const String getMidiNoteName (int noteNumber, + bool useSharps, + bool includeOctaveNumber, + int octaveNumForMiddleC) throw(); - /** Destructor. */ - ~TooltipWindow(); + /** Returns the frequency of a midi note number. - /** Changes the time before the tip appears. - This lets you change the value that was set in the constructor. + @see getMidiNoteName */ - void setMillisecondsBeforeTipAppears (const int newTimeMs = 700) throw(); + static const double getMidiNoteInHertz (int noteNumber) throw(); - /** A set of colour IDs to use to change the colour of various aspects of the tooltip. + /** Returns the standard name of a GM instrument. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + @param midiInstrumentNumber the program number 0 to 127 + @see getProgramChangeNumber + */ + static const String getGMInstrumentName (int midiInstrumentNumber) throw(); - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + /** Returns the name of a bank of GM instruments. + + @param midiBankNumber the bank, 0 to 15 */ - enum ColourIds - { - backgroundColourId = 0x1001b00, /**< The colour to fill the background with. */ - textColourId = 0x1001c00, /**< The colour to use for the text. */ - outlineColourId = 0x1001c10 /**< The colour to use to draw an outline around the tooltip. */ - }; + static const String getGMInstrumentBankName (int midiBankNumber) throw(); - juce_UseDebuggingNewOperator + /** Returns the standard name of a channel 10 percussion sound. -private: + @param midiNoteNumber the key number, 35 to 81 + */ + static const String getRhythmInstrumentName (int midiNoteNumber) throw(); - int millisecondsBeforeTipAppears; - int mouseX, mouseY, mouseClicks; - unsigned int lastCompChangeTime, lastHideTime; - Component* lastComponentUnderMouse; - bool changedCompsSinceShown; - String tipShowing, lastTipUnderMouse; + /** Returns the name of a controller type number. - void paint (Graphics& g); - void mouseEnter (const MouseEvent& e); - void timerCallback(); + @see getControllerNumber + */ + static const String getControllerName (int controllerNumber) throw(); - static const String getTipFor (Component* const c); - void showFor (Component* const c, const String& tip); - void hide(); + juce_UseDebuggingNewOperator - TooltipWindow (const TooltipWindow&); - const TooltipWindow& operator= (const TooltipWindow&); +private: + double timeStamp; + uint8* data; + int message, size; }; -#endif // __JUCE_TOOLTIPWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_TooltipWindow.h *********/ +#endif // __JUCE_MIDIMESSAGE_JUCEHEADER__ +/********* End of inlined file: juce_MidiMessage.h *********/ -class Button; +class MidiInput; /** - Used to receive callbacks when a button is clicked. + Receives midi messages from a midi input device. - @see Button::addButtonListener, Button::removeButtonListener + This class is overridden to handle incoming midi messages. See the MidiInput + class for more details. + + @see MidiInput */ -class JUCE_API ButtonListener +class JUCE_API MidiInputCallback { public: /** Destructor. */ - virtual ~ButtonListener() {} + virtual ~MidiInputCallback() {} - /** Called when the button is clicked. */ - virtual void buttonClicked (Button* button) = 0; + /** Receives an incoming message. - /** Called when the button's state changes. */ - virtual void buttonStateChanged (Button*) {} + A MidiInput object will call this method when a midi event arrives. It'll be + called on a high-priority system thread, so avoid doing anything time-consuming + in here, and avoid making any UI calls. You might find the MidiBuffer class helpful + for queueing incoming messages for use later. + + @param source the MidiInput object that generated the message + @param message the incoming message. The message's timestamp is set to a value + equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the + time when the message arrived. + */ + virtual void handleIncomingMidiMessage (MidiInput* source, + const MidiMessage& message) = 0; + + /** Notification sent each time a packet of a multi-packet sysex message arrives. + + If a long sysex message is broken up into multiple packets, this callback is made + for each packet that arrives until the message is finished, at which point + the normal handleIncomingMidiMessage() callback will be made with the entire + message. + + The message passed in will contain the start of a sysex, but won't be finished + with the terminating 0xf7 byte. + */ + virtual void handlePartialSysexMessage (MidiInput* source, + const uint8* messageData, + const int numBytesSoFar, + const double timestamp) + { + // (this bit is just to avoid compiler warnings about unused variables) + (void) source; (void) messageData; (void) numBytesSoFar; (void) timestamp; + } }; /** - A base class for buttons. + Represents a midi input device. - This contains all the logic for button behaviours such as enabling/disabling, - responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons - and radio groups, etc. + To create one of these, use the static getDevices() method to find out what inputs are + available, and then use the openDevice() method to try to open one. - @see TextButton, DrawableButton, ToggleButton + @see MidiOutput */ -class JUCE_API Button : public Component, - public SettableTooltipClient, - public ApplicationCommandManagerListener, - private KeyListener +class JUCE_API MidiInput { -protected: - - /** Creates a button. - - @param buttonName the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - */ - Button (const String& buttonName); - public: - /** Destructor. */ - virtual ~Button(); - /** Changes the button's text. + /** Returns a list of the available midi input devices. - @see getButtonText + You can open one of the devices by passing its index into the + openDevice() method. + + @see getDefaultDeviceIndex, openDevice */ - void setButtonText (const String& newText) throw(); + static const StringArray getDevices(); - /** Returns the text displayed in the button. + /** Returns the index of the default midi input device to use. - @see setButtonText + This refers to the index in the list returned by getDevices(). */ - const String getButtonText() const throw() { return text; } + static int getDefaultDeviceIndex(); - /** Returns true if the button is currently being held down by the mouse. + /** Tries to open one of the midi input devices. - @see isOver - */ - bool isDown() const throw(); + This will return a MidiInput object if it manages to open it. You can then + call start() and stop() on this device, and delete it when no longer needed. - /** Returns true if the mouse is currently over the button. + If the device can't be opened, this will return a null pointer. - This will be also be true if the mouse is being held down. + @param deviceIndex the index of a device from the list returned by getDevices() + @param callback the object that will receive the midi messages from this device. - @see isDown + @see MidiInputCallback, getDevices */ - bool isOver() const throw(); + static MidiInput* openDevice (int deviceIndex, + MidiInputCallback* callback); - /** A button has an on/off state associated with it, and this changes that. +#if JUCE_LINUX || JUCE_MAC || DOXYGEN + /** This will try to create a new midi input device (Not available on Windows). - By default buttons are 'off' and for simple buttons that you click to perform - an action you won't change this. Toggle buttons, however will want to - change their state when turned on or off. + This will attempt to create a new midi input device with the specified name, + for other apps to connect to. - @param shouldBeOn whether to set the button's toggle state to be on or - off. If it's a member of a button group, this will - always try to turn it on, and to turn off any other - buttons in the group - @param sendChangeNotification if true, a callback will be made to clicked(); if false - the button will be repainted but no notification will - be sent - @see getToggleState, setRadioGroupId + Returns 0 if a device can't be created. + + @param deviceName the name to use for the new device + @param callback the object that will receive the midi messages from this device. */ - void setToggleState (const bool shouldBeOn, - const bool sendChangeNotification); + static MidiInput* createNewDevice (const String& deviceName, + MidiInputCallback* callback); +#endif - /** Returns true if the button in 'on'. + /** Destructor. */ + virtual ~MidiInput(); - By default buttons are 'off' and for simple buttons that you click to perform - an action you won't change this. Toggle buttons, however will want to - change their state when turned on or off. + /** Returns the name of this device. + */ + virtual const String getName() const throw() { return name; } - @see setToggleState + /** Allows you to set a custom name for the device, in case you don't like the name + it was given when created. */ - bool getToggleState() const throw() { return isOn; } + virtual void setName (const String& newName) throw() { name = newName; } - /** This tells the button to automatically flip the toggle state when - the button is clicked. + /** Starts the device running. - If set to true, then before the clicked() callback occurs, the toggle-state - of the button is flipped. + After calling this, the device will start sending midi messages to the + MidiInputCallback object that was specified when the openDevice() method + was called. + + @see stop */ - void setClickingTogglesState (const bool shouldToggle) throw(); + virtual void start(); - /** Returns true if this button is set to be an automatic toggle-button. + /** Stops the device running. - This returns the last value that was passed to setClickingTogglesState(). + @see start */ - bool getClickingTogglesState() const throw(); - - /** Enables the button to act as a member of a mutually-exclusive group - of 'radio buttons'. + virtual void stop(); - If the group ID is set to a non-zero number, then this button will - act as part of a group of buttons with the same ID, only one of - which can be 'on' at the same time. Note that when it's part of - a group, clicking a toggle-button that's 'on' won't turn it off. + juce_UseDebuggingNewOperator - To find other buttons with the same ID, this button will search through - its sibling components for ToggleButtons, so all the buttons for a - particular group must be placed inside the same parent component. +protected: + String name; + void* internal; - Set the group ID back to zero if you want it to act as a normal toggle - button again. + MidiInput (const String& name); + MidiInput (const MidiInput&); +}; - @see getRadioGroupId - */ - void setRadioGroupId (const int newGroupId); +#endif // __JUCE_MIDIINPUT_JUCEHEADER__ +/********* End of inlined file: juce_MidiInput.h *********/ - /** Returns the ID of the group to which this button belongs. +/********* Start of inlined file: juce_MidiOutput.h *********/ +#ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ +#define __JUCE_MIDIOUTPUT_JUCEHEADER__ - (See setRadioGroupId() for an explanation of this). - */ - int getRadioGroupId() const throw() { return radioGroupId; } +/********* Start of inlined file: juce_MidiBuffer.h *********/ +#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ +#define __JUCE_MIDIBUFFER_JUCEHEADER__ - /** Registers a listener to receive events when this button's state changes. +/** + Holds a sequence of time-stamped midi events. - If the listener is already registered, this will not register it again. + Analogous to the AudioSampleBuffer, this holds a set of midi events with + integer time-stamps. The buffer is kept sorted in order of the time-stamps. - @see removeButtonListener - */ - void addButtonListener (ButtonListener* const newListener) throw(); + @see MidiMessage +*/ +class JUCE_API MidiBuffer +{ +public: - /** Removes a previously-registered button listener + /** Creates an empty MidiBuffer. */ + MidiBuffer() throw(); - @see addButtonListener - */ - void removeButtonListener (ButtonListener* const listener) throw(); + /** Creates a MidiBuffer containing a single midi message. */ + MidiBuffer (const MidiMessage& message) throw(); - /** Causes the button to act as if it's been clicked. + /** Creates a copy of another MidiBuffer. */ + MidiBuffer (const MidiBuffer& other) throw(); - This will asynchronously make the button draw itself going down and up, and - will then call back the clicked() method as if mouse was clicked on it. + /** Makes a copy of another MidiBuffer. */ + const MidiBuffer& operator= (const MidiBuffer& other) throw(); - @see clicked - */ - virtual void triggerClick(); + /** Destructor */ + ~MidiBuffer() throw(); - /** Sets a command ID for this button to automatically invoke when it's clicked. + /** Removes all events from the buffer. */ + void clear() throw(); - When the button is pressed, it will use the given manager to trigger the - command ID. + /** Removes all events between two times from the buffer. - Obviously be careful that the ApplicationCommandManager doesn't get deleted - before this button is. To disable the command triggering, call this method and - pass 0 for the parameters. + All events for which (start <= event position < start + numSamples) will + be removed. + */ + void clear (const int start, + const int numSamples) throw(); - If generateTooltip is true, then the button's tooltip will be automatically - generated based on the name of this command and its current shortcut key. + /** Returns true if the buffer is empty. - @see addShortcut, getCommandID + To actually retrieve the events, use a MidiBuffer::Iterator object */ - void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, - const int commandID, - const bool generateTooltip); + bool isEmpty() const throw(); - /** Returns the command ID that was set by setCommandToTrigger(). + /** Counts the number of events in the buffer. + + This is actually quite a slow operation, as it has to iterate through all + the events, so you might prefer to call isEmpty() if that's all you need + to know. */ - int getCommandID() const throw() { return commandID; } + int getNumEvents() const throw(); - /** Assigns a shortcut key to trigger the button. + /** Adds an event to the buffer. - The button registers itself with its top-level parent component for keypresses. + The sample number will be used to determine the position of the event in + the buffer, which is always kept sorted. The MidiMessage's timestamp is + ignored. - Note that a different way of linking buttons to keypresses is by using the - setCommandToTrigger() method to invoke a command. + If an event is added whose sample position is the same as one or more events + already in the buffer, the new event will be placed after the existing ones. - @see clearShortcuts + To retrieve events, use a MidiBuffer::Iterator object */ - void addShortcut (const KeyPress& key); + void addEvent (const MidiMessage& midiMessage, + const int sampleNumber) throw(); - /** Removes all key shortcuts that had been set for this button. + /** Adds an event to the buffer from raw midi data. - @see addShortcut - */ - void clearShortcuts(); + The sample number will be used to determine the position of the event in + the buffer, which is always kept sorted. - /** Returns true if the given keypress is a shortcut for this button. + If an event is added whose sample position is the same as one or more events + already in the buffer, the new event will be placed after the existing ones. - @see addShortcut - */ - bool isRegisteredForShortcut (const KeyPress& key) const throw(); + The event data will be inspected to calculate the number of bytes in length that + the midi event really takes up, so maxBytesOfMidiData may be longer than the data + that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes, + it'll actually only store 3 bytes. If the midi data is invalid, it might not + add an event at all. - /** Sets an auto-repeat speed for the button when it is held down. + To retrieve events, use a MidiBuffer::Iterator object + */ + void addEvent (const uint8* const rawMidiData, + const int maxBytesOfMidiData, + const int sampleNumber) throw(); - (Auto-repeat is disabled by default). + /** Adds some events from another buffer to this one. - @param initialDelayInMillisecs how long to wait after the mouse is pressed before - triggering the next click. If this is zero, auto-repeat - is disabled - @param repeatDelayInMillisecs the frequently subsequent repeated clicks should be - triggered - @param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will - get faster, the longer the button is held down, up to the - minimum interval specified here + @param otherBuffer the buffer containing the events you want to add + @param startSample the lowest sample number in the source buffer for which + events should be added. Any source events whose timestamp is + less than this will be ignored + @param numSamples the valid range of samples from the source buffer for which + events should be added - i.e. events in the source buffer whose + timestamp is greater than or equal to (startSample + numSamples) + will be ignored. If this value is less than 0, all events after + startSample will be taken. + @param sampleDeltaToAdd a value which will be added to the source timestamps of the events + that are added to this buffer */ - void setRepeatSpeed (const int initialDelayInMillisecs, - const int repeatDelayInMillisecs, - const int minimumDelayInMillisecs = -1) throw(); - - /** Sets whether the button click should happen when the mouse is pressed or released. + void addEvents (const MidiBuffer& otherBuffer, + const int startSample, + const int numSamples, + const int sampleDeltaToAdd) throw(); - By default the button is only considered to have been clicked when the mouse is - released, but setting this to true will make it call the clicked() method as soon - as the button is pressed. + /** Returns the sample number of the first event in the buffer. - This is useful if the button is being used to show a pop-up menu, as it allows - the click to be used as a drag onto the menu. + If the buffer's empty, this will just return 0. */ - void setTriggeredOnMouseDown (const bool isTriggeredOnMouseDown) throw(); + int getFirstEventTime() const throw(); - /** Returns the number of milliseconds since the last time the button - went into the 'down' state. - */ - uint32 getMillisecondsSinceButtonDown() const throw(); + /** Returns the sample number of the last event in the buffer. - /** (overridden from Component to do special stuff). */ - void setVisible (bool shouldBeVisible); + If the buffer's empty, this will just return 0. + */ + int getLastEventTime() const throw(); - /** Sets the tooltip for this button. + /** Exchanges the contents of this buffer with another one. - @see TooltipClient, TooltipWindow + This is a quick operation, because no memory allocating or copying is done, it + just swaps the internal state of the two buffers. */ - void setTooltip (const String& newTooltip); + void swap (MidiBuffer& other); - // (implementation of the TooltipClient method) - const String getTooltip(); + /** + Used to iterate through the events in a MidiBuffer. - /** A combination of these flags are used by setConnectedEdges(). + Note that altering the buffer while an iterator is using it isn't a + safe operation. + + @see MidiBuffer */ - enum ConnectedEdgeFlags + class Iterator { - ConnectedOnLeft = 1, - ConnectedOnRight = 2, - ConnectedOnTop = 4, - ConnectedOnBottom = 8 - }; + public: - /** Hints about which edges of the button might be connected to adjoining buttons. + /** Creates an Iterator for this MidiBuffer. */ + Iterator (const MidiBuffer& buffer) throw(); - The value passed in is a bitwise combination of any of the values in the - ConnectedEdgeFlags enum. + /** Destructor. */ + ~Iterator() throw(); - E.g. if you are placing two buttons adjacent to each other, you could use this to - indicate which edges are touching, and the LookAndFeel might choose to drawn them - without rounded corners on the edges that connect. It's only a hint, so the - LookAndFeel can choose to ignore it if it's not relevent for this type of - button. - */ - void setConnectedEdges (const int connectedEdgeFlags) throw(); + /** Repositions the iterator so that the next event retrieved will be the first + one whose sample position is at greater than or equal to the given position. + */ + void setNextSamplePosition (const int samplePosition) throw(); - /** Returns the set of flags passed into setConnectedEdges(). */ - int getConnectedEdgeFlags() const throw() { return connectedEdgeFlags; } + /** Retrieves a copy of the next event from the buffer. - /** Indicates whether the button adjoins another one on its left edge. - @see setConnectedEdges - */ - bool isConnectedOnLeft() const throw() { return (connectedEdgeFlags & ConnectedOnLeft) != 0; } + @param result on return, this will be the message (the MidiMessage's timestamp + is not set) + @param samplePosition on return, this will be the position of the event + @returns true if an event was found, or false if the iterator has reached + the end of the buffer + */ + bool getNextEvent (MidiMessage& result, + int& samplePosition) throw(); - /** Indicates whether the button adjoins another one on its right edge. - @see setConnectedEdges - */ - bool isConnectedOnRight() const throw() { return (connectedEdgeFlags & ConnectedOnRight) != 0; } + /** Retrieves the next event from the buffer. - /** Indicates whether the button adjoins another one on its top edge. - @see setConnectedEdges - */ - bool isConnectedOnTop() const throw() { return (connectedEdgeFlags & ConnectedOnTop) != 0; } + @param midiData on return, this pointer will be set to a block of data containing + the midi message. Note that to make it fast, this is a pointer + directly into the MidiBuffer's internal data, so is only valid + temporarily until the MidiBuffer is altered. + @param numBytesOfMidiData on return, this is the number of bytes of data used by the + midi message + @param samplePosition on return, this will be the position of the event + @returns true if an event was found, or false if the iterator has reached + the end of the buffer + */ + bool getNextEvent (const uint8* &midiData, + int& numBytesOfMidiData, + int& samplePosition) throw(); - /** Indicates whether the button adjoins another one on its bottom edge. - @see setConnectedEdges - */ - bool isConnectedOnBottom() const throw() { return (connectedEdgeFlags & ConnectedOnBottom) != 0; } + juce_UseDebuggingNewOperator - /** Used by setState(). */ - enum ButtonState - { - buttonNormal, - buttonOver, - buttonDown + private: + const MidiBuffer& buffer; + const uint8* data; + + Iterator (const Iterator&); + const Iterator& operator= (const Iterator&); }; - /** Can be used to force the button into a particular state. + juce_UseDebuggingNewOperator - This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks - from happening. +private: + friend class MidiBuffer::Iterator; + ArrayAllocationBase data; + int bytesUsed; - The state that you set here will only last until it is automatically changed when the mouse - enters or exits the button, or the mouse-button is pressed or released. - */ - void setState (const ButtonState newState); + uint8* findEventAfter (uint8* d, const int samplePosition) const throw(); +}; - juce_UseDebuggingNewOperator +#endif // __JUCE_MIDIBUFFER_JUCEHEADER__ +/********* End of inlined file: juce_MidiBuffer.h *********/ -protected: +/** + Represents a midi output device. - /** This method is called when the button has been clicked. + To create one of these, use the static getDevices() method to find out what + outputs are available, then use the openDevice() method to try to open one. - Subclasses can override this to perform whatever they actions they need - to do. + @see MidiInput +*/ +class JUCE_API MidiOutput : private Thread +{ +public: - Alternatively, a ButtonListener can be added to the button, and these listeners - will be called when the click occurs. + /** Returns a list of the available midi output devices. - @see triggerClick - */ - virtual void clicked(); + You can open one of the devices by passing its index into the + openDevice() method. - /** This method is called when the button has been clicked. + @see getDefaultDeviceIndex, openDevice + */ + static const StringArray getDevices(); - By default it just calls clicked(), but you might want to override it to handle - things like clicking when a modifier key is pressed, etc. + /** Returns the index of the default midi output device to use. - @see ModifierKeys + This refers to the index in the list returned by getDevices(). */ - virtual void clicked (const ModifierKeys& modifiers); + static int getDefaultDeviceIndex(); - /** Subclasses should override this to actually paint the button's contents. + /** Tries to open one of the midi output devices. - It's better to use this than the paint method, because it gives you information - about the over/down state of the button. + This will return a MidiOutput object if it manages to open it. You can then + send messages to this device, and delete it when no longer needed. - @param g the graphics context to use - @param isMouseOverButton true if the button is either in the 'over' or - 'down' state - @param isButtonDown true if the button should be drawn in the 'down' position + If the device can't be opened, this will return a null pointer. + + @param deviceIndex the index of a device from the list returned by getDevices() + @see getDevices */ - virtual void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown) = 0; + static MidiOutput* openDevice (int deviceIndex); - /** Called when the button's up/down/over state changes. +#if JUCE_LINUX || JUCE_MAC || DOXYGEN + /** This will try to create a new midi output device (Not available on Windows). - Subclasses can override this if they need to do something special when the button - goes up or down. + This will attempt to create a new midi output device that other apps can connect + to and use as their midi input. - @see isDown, isOver + Returns 0 if a device can't be created. + + @param deviceName the name to use for the new device */ - virtual void buttonStateChanged(); + static MidiOutput* createNewDevice (const String& deviceName); +#endif - /** @internal */ - virtual void internalClickCallback (const ModifierKeys& modifiers); - /** @internal */ - void handleCommandMessage (int commandId); - /** @internal */ - void mouseEnter (const MouseEvent& e); - /** @internal */ - void mouseExit (const MouseEvent& e); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - bool keyPressed (const KeyPress& key, Component* originatingComponent); - /** @internal */ - bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - void focusGained (FocusChangeType cause); - /** @internal */ - void focusLost (FocusChangeType cause); - /** @internal */ - void enablementChanged(); - /** @internal */ - void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&); - /** @internal */ - void applicationCommandListChanged(); + /** Destructor. */ + virtual ~MidiOutput(); -private: + /** Makes this device output a midi message. - Array shortcuts; - Component* keySource; - String text; - SortedSet buttonListeners; + @see MidiMessage + */ + virtual void sendMessageNow (const MidiMessage& message); - friend class InternalButtonRepeatTimer; - Timer* repeatTimer; - uint32 buttonPressTime, lastTimeCallbackTime; - ApplicationCommandManager* commandManagerToUse; - int autoRepeatDelay, autoRepeatSpeed, autoRepeatMinimumDelay; - int radioGroupId, commandID, connectedEdgeFlags; - ButtonState buttonState; + /** Sends a midi reset to the device. */ + virtual void reset(); - bool isOn : 1; - bool clickTogglesState : 1; - bool needsToRelease : 1; - bool needsRepainting : 1; - bool isKeyDown : 1; - bool triggerOnMouseDown : 1; - bool generateTooltip : 1; + /** Returns the current volume setting for this device. */ + virtual bool getVolume (float& leftVol, + float& rightVol); - void repeatTimerCallback() throw(); - Timer& getRepeatTimer() throw(); + /** Changes the overall volume for this device. */ + virtual void setVolume (float leftVol, + float rightVol); - ButtonState updateState (const MouseEvent* const e) throw(); - bool isShortcutPressed() const throw(); - void turnOffOtherButtonsInGroup (const bool sendChangeNotification); + /** This lets you supply a block of messages that will be sent out at some point + in the future. - void flashButtonState() throw(); - void sendClickMessage (const ModifierKeys& modifiers); - void sendStateMessage(); + The MidiOutput class has an internal thread that can send out timestamped + messages - this appends a set of messages to its internal buffer, ready for + sending. - Button (const Button&); - const Button& operator= (const Button&); -}; + This will only work if you've already started the thread with startBackgroundThread(). -#endif // __JUCE_BUTTON_JUCEHEADER__ -/********* End of inlined file: juce_Button.h *********/ + A time is supplied, at which the block of messages should be sent. This time uses + the same time base as Time::getMillisecondCounter(), and must be in the future. -class ScrollBar; + The samplesPerSecondForBuffer parameter indicates the number of samples per second + used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the + samplesPerSecondForBuffer value is needed to convert this sample position to a + real time. + */ + virtual void sendBlockOfMessages (const MidiBuffer& buffer, + const double millisecondCounterToStartAt, + double samplesPerSecondForBuffer) throw(); -/** - A class for receiving events from a ScrollBar. + /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). + */ + virtual void clearAllPendingMessages() throw(); - You can register a ScrollBarListener with a ScrollBar using the ScrollBar::addListener() - method, and it will be called when the bar's position changes. + /** Starts up a background thread so that the device can send blocks of data. - @see ScrollBar::addListener, ScrollBar::removeListener -*/ -class JUCE_API ScrollBarListener -{ -public: - /** Destructor. */ - virtual ~ScrollBarListener() {} + Call this to get the device ready, before using sendBlockOfMessages(). + */ + virtual void startBackgroundThread() throw(); - /** Called when a ScrollBar is moved. + /** Stops the background thread, and clears any pending midi events. - @param scrollBarThatHasMoved the bar that has moved - @param newRangeStart the new range start of this bar + @see startBackgroundThread */ - virtual void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, - const double newRangeStart) = 0; -}; + virtual void stopBackgroundThread() throw(); -/** - A scrollbar component. + juce_UseDebuggingNewOperator - To use a scrollbar, set up its total range using the setRangeLimits() method - this - sets the range of values it can represent. Then you can use setCurrentRange() to - change the position and size of the scrollbar's 'thumb'. +protected: + void* internal; - Registering a ScrollBarListener with the scrollbar will allow you to find out when - the user moves it, and you can use the getCurrentRangeStart() to find out where - they moved it to. + struct PendingMessage + { + PendingMessage (const uint8* const data, const int len, const double sampleNumber) throw(); - The scrollbar will adjust its own visibility according to whether its thumb size - allows it to actually be scrolled. + MidiMessage message; + PendingMessage* next; - For most purposes, it's probably easier to use a ViewportContainer or ListBox - instead of handling a scrollbar directly. + juce_UseDebuggingNewOperator + }; - @see ScrollBarListener + CriticalSection lock; + PendingMessage* firstMessage; + + MidiOutput() throw(); + MidiOutput (const MidiOutput&); + + void run(); +}; + +#endif // __JUCE_MIDIOUTPUT_JUCEHEADER__ +/********* End of inlined file: juce_MidiOutput.h *********/ + +/********* Start of inlined file: juce_ComboBox.h *********/ +#ifndef __JUCE_COMBOBOX_JUCEHEADER__ +#define __JUCE_COMBOBOX_JUCEHEADER__ + +/********* Start of inlined file: juce_Label.h *********/ +#ifndef __JUCE_LABEL_JUCEHEADER__ +#define __JUCE_LABEL_JUCEHEADER__ + +/********* Start of inlined file: juce_ComponentDeletionWatcher.h *********/ +#ifndef __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ +#define __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ + +/** + Object for monitoring a component, and later testing whether it's still valid. + + Slightly obscure, this one, but it's used internally for making sure that + after some callbacks, a component hasn't been deleted. It's more reliable than + just using isValidComponent(), which can provide false-positives if a new + component is created at the same memory location as an old one. */ -class JUCE_API ScrollBar : public Component, - public AsyncUpdater, - private Timer +class JUCE_API ComponentDeletionWatcher { public: - /** Creates a Scrollbar. + /** Creates a watcher for a given component. - @param isVertical whether it should be a vertical or horizontal bar - @param buttonsAreVisible whether to show the up/down or left/right buttons + The component must be valid at the time it's passed in. */ - ScrollBar (const bool isVertical, - const bool buttonsAreVisible = true); + ComponentDeletionWatcher (const Component* const componentToWatch) throw(); /** Destructor. */ - ~ScrollBar(); - - /** Returns true if the scrollbar is vertical, false if it's horizontal. */ - bool isVertical() const throw() { return vertical; } - - /** Changes the scrollbar's direction. - - You'll also need to resize the bar appropriately - this just changes its internal - layout. + ~ComponentDeletionWatcher() throw(); - @param shouldBeVertical true makes it vertical; false makes it horizontal. + /** Returns true if the component has been deleted since the time that this + object was created. */ - void setOrientation (const bool shouldBeVertical) throw(); + bool hasBeenDeleted() const throw(); - /** Shows or hides the scrollbar's buttons. */ - void setButtonVisibility (const bool buttonsAreVisible); + /** Returns the component that's being watched, or null if it has been deleted. */ + const Component* getComponent() const throw(); - /** Tells the scrollbar whether to make itself invisible when not needed. + juce_UseDebuggingNewOperator - The default behaviour is for a scrollbar to become invisible when the thumb - fills the whole of its range (i.e. when it can't be moved). Setting this - value to false forces the bar to always be visible. - */ - void setAutoHide (const bool shouldHideWhenFullRange); +private: + const Component* const componentToWatch; + const uint32 componentUID; - /** Sets the minimum and maximum values that the bar will move between. + ComponentDeletionWatcher (const ComponentDeletionWatcher&); + const ComponentDeletionWatcher& operator= (const ComponentDeletionWatcher&); +}; - The bar's thumb will always be constrained so that the top of the thumb - will be >= minimum, and the bottom of the thumb <= maximum. +#endif // __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ +/********* End of inlined file: juce_ComponentDeletionWatcher.h *********/ - @see setCurrentRange - */ - void setRangeLimits (const double minimum, - const double maximum) throw(); +/********* Start of inlined file: juce_TextEditor.h *********/ +#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ +#define __JUCE_TEXTEDITOR_JUCEHEADER__ - /** Returns the lower value that the thumb can be set to. +/********* Start of inlined file: juce_Viewport.h *********/ +#ifndef __JUCE_VIEWPORT_JUCEHEADER__ +#define __JUCE_VIEWPORT_JUCEHEADER__ - This is the value set by setRangeLimits(). - */ - double getMinimumRangeLimit() const throw() { return minimum; } +/********* Start of inlined file: juce_ScrollBar.h *********/ +#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ +#define __JUCE_SCROLLBAR_JUCEHEADER__ - /** Returns the upper value that the thumb can be set to. +/********* Start of inlined file: juce_Button.h *********/ +#ifndef __JUCE_BUTTON_JUCEHEADER__ +#define __JUCE_BUTTON_JUCEHEADER__ - This is the value set by setRangeLimits(). - */ - double getMaximumRangeLimit() const throw() { return maximum; } +/********* Start of inlined file: juce_TooltipWindow.h *********/ +#ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ +#define __JUCE_TOOLTIPWINDOW_JUCEHEADER__ - /** Changes the position of the scrollbar's 'thumb'. +/********* Start of inlined file: juce_TooltipClient.h *********/ +#ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ +#define __JUCE_TOOLTIPCLIENT_JUCEHEADER__ - This sets both the position and size of the thumb - to just set the position without - changing the size, you can use setCurrentRangeStart(). +/** + Components that want to use pop-up tooltips should implement this interface. - If this method call actually changes the scrollbar's position, it will trigger an - asynchronous call to ScrollBarListener::scrollBarMoved() for all the listeners that - are registered. + A TooltipWindow will wait for the mouse to hover over a component that + implements the TooltipClient interface, and when it finds one, it will display + the tooltip returned by its getTooltip() method. - @param newStart the top (or left) of the thumb, in the range - getMinimumRangeLimit() <= newStart <= getMaximumRangeLimit(). If the - value is beyond these limits, it will be clipped. - @param newSize the size of the thumb, such that - getMinimumRangeLimit() <= newStart + newSize <= getMaximumRangeLimit(). If the - size is beyond these limits, it will be clipped. - @see setCurrentRangeStart, getCurrentRangeStart, getCurrentRangeSize - */ - void setCurrentRange (double newStart, - double newSize) throw(); + @see TooltipWindow, SettableTooltipClient +*/ +class JUCE_API TooltipClient +{ +public: + /** Destructor. */ + virtual ~TooltipClient() {} - /** Moves the bar's thumb position. + /** Returns the string that this object wants to show as its tooltip. */ + virtual const String getTooltip() = 0; +}; - This will move the thumb position without changing the thumb size. Note - that the maximum thumb start position is (getMaximumRangeLimit() - getCurrentRangeSize()). +/** + An implementation of TooltipClient that stores the tooltip string and a method + for changing it. - If this method call actually changes the scrollbar's position, it will trigger an - asynchronous call to ScrollBarListener::scrollBarMoved() for all the listeners that - are registered. + This makes it easy to add a tooltip to a custom component, by simply adding this + as a base class and calling setTooltip(). - @see setCurrentRange - */ - void setCurrentRangeStart (double newStart) throw(); + Many of the Juce widgets already use this as a base class to implement their + tooltips. - /** Returns the position of the top of the thumb. + @see TooltipClient, TooltipWindow +*/ +class JUCE_API SettableTooltipClient : public TooltipClient +{ +public: - @see setCurrentRangeStart - */ - double getCurrentRangeStart() const throw() { return rangeStart; } + /** Destructor. */ + virtual ~SettableTooltipClient() {} - /** Returns the current size of the thumb. + virtual void setTooltip (const String& newTooltip) { tooltipString = newTooltip; } - @see setCurrentRange - */ - double getCurrentRangeSize() const throw() { return rangeSize; } + virtual const String getTooltip() { return tooltipString; } - /** Sets the amount by which the up and down buttons will move the bar. + juce_UseDebuggingNewOperator - The value here is in terms of the total range, and is added or subtracted - from the thumb position when the user clicks an up/down (or left/right) button. - */ - void setSingleStepSize (const double newSingleStepSize) throw(); +protected: + String tooltipString; +}; - /** Moves the scrollbar by a number of single-steps. +#endif // __JUCE_TOOLTIPCLIENT_JUCEHEADER__ +/********* End of inlined file: juce_TooltipClient.h *********/ - This will move the bar by a multiple of its single-step interval (as - specified using the setSingleStepSize() method). +/** + A window that displays a pop-up tooltip when the mouse hovers over another component. - A positive value here will move the bar down or to the right, a negative - value moves it up or to the left. - */ - void moveScrollbarInSteps (const int howManySteps) throw(); + To enable tooltips in your app, just create a single instance of a TooltipWindow + object. - /** Moves the scroll bar up or down in pages. + The TooltipWindow object will then stay invisible, waiting until the mouse + hovers for the specified length of time - it will then see if it's currently + over a component which implements the TooltipClient interface, and if so, + it will make itself visible to show the tooltip in the appropriate place. - This will move the bar by a multiple of its current thumb size, effectively - doing a page-up or down. + @see TooltipClient, SettableTooltipClient +*/ +class JUCE_API TooltipWindow : public Component, + private Timer +{ +public: - A positive value here will move the bar down or to the right, a negative - value moves it up or to the left. - */ - void moveScrollbarInPages (const int howManyPages) throw(); + /** Creates a tooltip window. - /** Scrolls to the top (or left). + Make sure your app only creates one instance of this class, otherwise you'll + get multiple overlaid tooltips appearing. The window will initially be invisible + and will make itself visible when it needs to display a tip. - This is the same as calling setCurrentRangeStart (getMinimumRangeLimit()); - */ - void scrollToTop() throw(); + To change the style of tooltips, see the LookAndFeel class for its tooltip + methods. - /** Scrolls to the bottom (or right). + @param parentComponent if set to 0, the TooltipWindow will appear on the desktop, + otherwise the tooltip will be added to the given parent + component. + @param millisecondsBeforeTipAppears the time for which the mouse has to stay still + before a tooltip will be shown - This is the same as calling setCurrentRangeStart (getMaximumRangeLimit() - getCurrentRangeSize()); + @see TooltipClient, LookAndFeel::drawTooltip, LookAndFeel::getTooltipSize */ - void scrollToBottom() throw(); - - /** Changes the delay before the up and down buttons autorepeat when they are held - down. + TooltipWindow (Component* parentComponent = 0, + const int millisecondsBeforeTipAppears = 700); - For an explanation of what the parameters are for, see Button::setRepeatSpeed(). + /** Destructor. */ + ~TooltipWindow(); - @see Button::setRepeatSpeed + /** Changes the time before the tip appears. + This lets you change the value that was set in the constructor. */ - void setButtonRepeatSpeed (const int initialDelayInMillisecs, - const int repeatDelayInMillisecs, - const int minimumDelayInMillisecs = -1) throw(); + void setMillisecondsBeforeTipAppears (const int newTimeMs = 700) throw(); - /** A set of colour IDs to use to change the colour of various aspects of the component. + /** A set of colour IDs to use to change the colour of various aspects of the tooltip. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @@ -32087,10589 +31444,10666 @@ public: */ enum ColourIds { - backgroundColourId = 0x1000300, /**< The background colour of the scrollbar. */ - thumbColourId = 0x1000400, /**< A base colour to use for the thumb. The look and feel will probably use variations on this colour. */ - trackColourId = 0x1000401 /**< A base colour to use for the slot area of the bar. The look and feel will probably use variations on this colour. */ + backgroundColourId = 0x1001b00, /**< The colour to fill the background with. */ + textColourId = 0x1001c00, /**< The colour to use for the text. */ + outlineColourId = 0x1001c10 /**< The colour to use to draw an outline around the tooltip. */ }; - /** Registers a listener that will be called when the scrollbar is moved. */ - void addListener (ScrollBarListener* const listener) throw(); - - /** Deregisters a previously-registered listener. */ - void removeListener (ScrollBarListener* const listener) throw(); - - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - void handleAsyncUpdate(); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - juce_UseDebuggingNewOperator private: - double minimum, maximum; - double rangeStart, rangeSize; - double singleStepSize, dragStartRange; - int thumbAreaStart, thumbAreaSize, thumbStart, thumbSize; - int dragStartMousePos, lastMousePos; - int initialDelayInMillisecs, repeatDelayInMillisecs, minimumDelayInMillisecs; - bool vertical, isDraggingThumb, alwaysVisible; - Button* upButton; - Button* downButton; - SortedSet listeners; + int millisecondsBeforeTipAppears; + int mouseX, mouseY, mouseClicks; + unsigned int lastCompChangeTime, lastHideTime; + Component* lastComponentUnderMouse; + bool changedCompsSinceShown; + String tipShowing, lastTipUnderMouse; - void updateThumbPosition() throw(); + void paint (Graphics& g); + void mouseEnter (const MouseEvent& e); void timerCallback(); - ScrollBar (const ScrollBar&); - const ScrollBar& operator= (const ScrollBar&); + static const String getTipFor (Component* const c); + void showFor (Component* const c, const String& tip); + void hide(); + + TooltipWindow (const TooltipWindow&); + const TooltipWindow& operator= (const TooltipWindow&); }; -#endif // __JUCE_SCROLLBAR_JUCEHEADER__ -/********* End of inlined file: juce_ScrollBar.h *********/ +#endif // __JUCE_TOOLTIPWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_TooltipWindow.h *********/ + +class Button; /** - A Viewport is used to contain a larger child component, and allows the child - to be automatically scrolled around. + Used to receive callbacks when a button is clicked. - To use a Viewport, just create one and set the component that goes inside it - using the setViewedComponent() method. When the child component changes size, - the Viewport will adjust its scrollbars accordingly. + @see Button::addButtonListener, Button::removeButtonListener +*/ +class JUCE_API ButtonListener +{ +public: + /** Destructor. */ + virtual ~ButtonListener() {} - A subclass of the viewport can be created which will receive calls to its - visibleAreaChanged() method when the subcomponent changes position or size. + /** Called when the button is clicked. */ + virtual void buttonClicked (Button* button) = 0; + + /** Called when the button's state changes. */ + virtual void buttonStateChanged (Button*) {} +}; + +/** + A base class for buttons. + + This contains all the logic for button behaviours such as enabling/disabling, + responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons + and radio groups, etc. + @see TextButton, DrawableButton, ToggleButton */ -class JUCE_API Viewport : public Component, - private ComponentListener, - private ScrollBarListener +class JUCE_API Button : public Component, + public SettableTooltipClient, + public ApplicationCommandManagerListener, + private KeyListener { -public: +protected: - /** Creates a Viewport. + /** Creates a button. - The viewport is initially empty - use the setViewedComponent() method to - add a child component for it to manage. + @param buttonName the text to put in the button (the component's name is also + initially set to this string, but these can be changed later + using the setName() and setButtonText() methods) */ - Viewport (const String& componentName = String::empty); + Button (const String& buttonName); +public: /** Destructor. */ - ~Viewport(); + virtual ~Button(); - /** Sets the component that this viewport will contain and scroll around. + /** Changes the button's text. - This will add the given component to this Viewport and position it at - (0, 0). + @see getButtonText + */ + void setButtonText (const String& newText) throw(); - (Don't add or remove any child components directly using the normal - Component::addChildComponent() methods). + /** Returns the text displayed in the button. - @param newViewedComponent the component to add to this viewport (this pointer - may be null). The component passed in will be deleted - by the Viewport when it's no longer needed - @see getViewedComponent + @see setButtonText */ - void setViewedComponent (Component* const newViewedComponent); + const String getButtonText() const throw() { return text; } - /** Returns the component that's currently being used inside the Viewport. + /** Returns true if the button is currently being held down by the mouse. - @see setViewedComponent + @see isOver */ - Component* getViewedComponent() const throw() { return contentComp; } - - /** Changes the position of the viewed component. + bool isDown() const throw(); - The inner component will be moved so that the pixel at the top left of - the viewport will be the pixel at position (xPixelsOffset, yPixelsOffset) - within the inner component. + /** Returns true if the mouse is currently over the button. - This will update the scrollbars and might cause a call to visibleAreaChanged(). + This will be also be true if the mouse is being held down. - @see getViewPositionX, getViewPositionY, setViewPositionProportionately + @see isDown */ - void setViewPosition (const int xPixelsOffset, - const int yPixelsOffset); + bool isOver() const throw(); - /** Changes the view position as a proportion of the distance it can move. + /** A button has an on/off state associated with it, and this changes that. - The values here are from 0.0 to 1.0 - where (0, 0) would put the - visible area in the top-left, and (1, 1) would put it as far down and - to the right as it's possible to go whilst keeping the child component - on-screen. + By default buttons are 'off' and for simple buttons that you click to perform + an action you won't change this. Toggle buttons, however will want to + change their state when turned on or off. + + @param shouldBeOn whether to set the button's toggle state to be on or + off. If it's a member of a button group, this will + always try to turn it on, and to turn off any other + buttons in the group + @param sendChangeNotification if true, a callback will be made to clicked(); if false + the button will be repainted but no notification will + be sent + @see getToggleState, setRadioGroupId */ - void setViewPositionProportionately (const double proportionX, - const double proportionY); + void setToggleState (const bool shouldBeOn, + const bool sendChangeNotification); - /** If the specified position is at the edges of the viewport, this method scrolls - the viewport to bring that position nearer to the centre. + /** Returns true if the button in 'on'. - Call this if you're dragging an object inside a viewport and want to make it scroll - when the user approaches an edge. You might also find Component::beginDragAutoRepeat() - useful when auto-scrolling. + By default buttons are 'off' and for simple buttons that you click to perform + an action you won't change this. Toggle buttons, however will want to + change their state when turned on or off. - @param mouseX the x position, relative to the Viewport's top-left - @param mouseY the y position, relative to the Viewport's top-left - @param distanceFromEdge specifies how close to an edge the position needs to be - before the viewport should scroll in that direction - @param maximumSpeed the maximum number of pixels that the viewport is allowed - to scroll by. - @returns true if the viewport was scrolled + @see setToggleState */ - bool autoScroll (int mouseX, int mouseY, int distanceFromEdge, int maximumSpeed); + bool getToggleState() const throw() { return isOn; } - /** Returns the position within the child component of the top-left of its visible area. - @see getViewWidth, setViewPosition - */ - int getViewPositionX() const throw() { return lastVX; } + /** This tells the button to automatically flip the toggle state when + the button is clicked. - /** Returns the position within the child component of the top-left of its visible area. - @see getViewHeight, setViewPosition + If set to true, then before the clicked() callback occurs, the toggle-state + of the button is flipped. */ - int getViewPositionY() const throw() { return lastVY; } + void setClickingTogglesState (const bool shouldToggle) throw(); - /** Returns the width of the visible area of the child component. + /** Returns true if this button is set to be an automatic toggle-button. - This may be less than the width of this Viewport if there's a vertical scrollbar - or if the child component is itself smaller. + This returns the last value that was passed to setClickingTogglesState(). */ - int getViewWidth() const throw() { return lastVW; } + bool getClickingTogglesState() const throw(); - /** Returns the height of the visible area of the child component. + /** Enables the button to act as a member of a mutually-exclusive group + of 'radio buttons'. - This may be less than the height of this Viewport if there's a horizontal scrollbar - or if the child component is itself smaller. - */ - int getViewHeight() const throw() { return lastVH; } + If the group ID is set to a non-zero number, then this button will + act as part of a group of buttons with the same ID, only one of + which can be 'on' at the same time. Note that when it's part of + a group, clicking a toggle-button that's 'on' won't turn it off. - /** Returns the width available within this component for the contents. + To find other buttons with the same ID, this button will search through + its sibling components for ToggleButtons, so all the buttons for a + particular group must be placed inside the same parent component. - This will be the width of the viewport component minus the width of a - vertical scrollbar (if visible). + Set the group ID back to zero if you want it to act as a normal toggle + button again. + + @see getRadioGroupId */ - int getMaximumVisibleWidth() const throw(); + void setRadioGroupId (const int newGroupId); - /** Returns the height available within this component for the contents. + /** Returns the ID of the group to which this button belongs. - This will be the height of the viewport component minus the space taken up - by a horizontal scrollbar (if visible). + (See setRadioGroupId() for an explanation of this). */ - int getMaximumVisibleHeight() const throw(); + int getRadioGroupId() const throw() { return radioGroupId; } - /** Callback method that is called when the visible area changes. + /** Registers a listener to receive events when this button's state changes. - This will be called when the visible area is moved either be scrolling or - by calls to setViewPosition(), etc. + If the listener is already registered, this will not register it again. + + @see removeButtonListener */ - virtual void visibleAreaChanged (int visibleX, int visibleY, - int visibleW, int visibleH); + void addButtonListener (ButtonListener* const newListener) throw(); - /** Turns scrollbars on or off. + /** Removes a previously-registered button listener - If set to false, the scrollbars won't ever appear. When true (the default) - they will appear only when needed. + @see addButtonListener */ - void setScrollBarsShown (const bool showVerticalScrollbarIfNeeded, - const bool showHorizontalScrollbarIfNeeded); + void removeButtonListener (ButtonListener* const listener) throw(); - /** True if the vertical scrollbar is enabled. - @see setScrollBarsShown - */ - bool isVerticalScrollBarShown() const throw() { return showVScrollbar; } + /** Causes the button to act as if it's been clicked. - /** True if the horizontal scrollbar is enabled. - @see setScrollBarsShown + This will asynchronously make the button draw itself going down and up, and + will then call back the clicked() method as if mouse was clicked on it. + + @see clicked */ - bool isHorizontalScrollBarShown() const throw() { return showHScrollbar; } + virtual void triggerClick(); - /** Changes the width of the scrollbars. + /** Sets a command ID for this button to automatically invoke when it's clicked. - If this isn't specified, the default width from the LookAndFeel class will be used. + When the button is pressed, it will use the given manager to trigger the + command ID. - @see LookAndFeel::getDefaultScrollbarWidth - */ - void setScrollBarThickness (const int thickness); + Obviously be careful that the ApplicationCommandManager doesn't get deleted + before this button is. To disable the command triggering, call this method and + pass 0 for the parameters. - /** Returns the thickness of the scrollbars. + If generateTooltip is true, then the button's tooltip will be automatically + generated based on the name of this command and its current shortcut key. - @see setScrollBarThickness + @see addShortcut, getCommandID */ - int getScrollBarThickness() const throw(); + void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, + const int commandID, + const bool generateTooltip); - /** Changes the distance that a single-step click on a scrollbar button - will move the viewport. + /** Returns the command ID that was set by setCommandToTrigger(). */ - void setSingleStepSizes (const int stepX, const int stepY); + int getCommandID() const throw() { return commandID; } - /** Shows or hides the buttons on any scrollbars that are used. + /** Assigns a shortcut key to trigger the button. - @see ScrollBar::setButtonVisibility - */ - void setScrollBarButtonVisibility (const bool buttonsVisible); + The button registers itself with its top-level parent component for keypresses. - /** Returns a pointer to the scrollbar component being used. + Note that a different way of linking buttons to keypresses is by using the + setCommandToTrigger() method to invoke a command. - Handy if you need to customise the bar somehow. + @see clearShortcuts */ - ScrollBar* getVerticalScrollBar() const throw() { return verticalScrollBar; } + void addShortcut (const KeyPress& key); - /** Returns a pointer to the scrollbar component being used. + /** Removes all key shortcuts that had been set for this button. - Handy if you need to customise the bar somehow. + @see addShortcut */ - ScrollBar* getHorizontalScrollBar() const throw() { return horizontalScrollBar; } + void clearShortcuts(); - juce_UseDebuggingNewOperator + /** Returns true if the given keypress is a shortcut for this button. - /** @internal */ - void resized(); - /** @internal */ - void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart); - /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); - /** @internal */ - bool useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + @see addShortcut + */ + bool isRegisteredForShortcut (const KeyPress& key) const throw(); -private: - Component* contentComp; - int lastVX, lastVY, lastVW, lastVH; - int scrollBarThickness; - int singleStepX, singleStepY; - bool showHScrollbar, showVScrollbar; - Component* contentHolder; - ScrollBar* verticalScrollBar; - ScrollBar* horizontalScrollBar; + /** Sets an auto-repeat speed for the button when it is held down. - void updateVisibleRegion(); - Viewport (const Viewport&); - const Viewport& operator= (const Viewport&); -}; + (Auto-repeat is disabled by default). -#endif // __JUCE_VIEWPORT_JUCEHEADER__ -/********* End of inlined file: juce_Viewport.h *********/ + @param initialDelayInMillisecs how long to wait after the mouse is pressed before + triggering the next click. If this is zero, auto-repeat + is disabled + @param repeatDelayInMillisecs the frequently subsequent repeated clicks should be + triggered + @param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will + get faster, the longer the button is held down, up to the + minimum interval specified here + */ + void setRepeatSpeed (const int initialDelayInMillisecs, + const int repeatDelayInMillisecs, + const int minimumDelayInMillisecs = -1) throw(); -/** - A panel that holds a list of PropertyComponent objects. + /** Sets whether the button click should happen when the mouse is pressed or released. - This panel displays a list of PropertyComponents, and allows them to be organised - into collapsible sections. + By default the button is only considered to have been clicked when the mouse is + released, but setting this to true will make it call the clicked() method as soon + as the button is pressed. - To use, simply create one of these and add your properties to it with addProperties() - or addSection(). + This is useful if the button is being used to show a pop-up menu, as it allows + the click to be used as a drag onto the menu. + */ + void setTriggeredOnMouseDown (const bool isTriggeredOnMouseDown) throw(); - @see PropertyComponent -*/ -class JUCE_API PropertyPanel : public Component -{ -public: + /** Returns the number of milliseconds since the last time the button + went into the 'down' state. + */ + uint32 getMillisecondsSinceButtonDown() const throw(); - /** Creates an empty property panel. */ - PropertyPanel(); + /** (overridden from Component to do special stuff). */ + void setVisible (bool shouldBeVisible); - /** Destructor. */ - ~PropertyPanel(); + /** Sets the tooltip for this button. - /** Deletes all property components from the panel. + @see TooltipClient, TooltipWindow */ - void clear(); - - /** Adds a set of properties to the panel. + void setTooltip (const String& newTooltip); - The components in the list will be owned by this object and will be automatically - deleted later on when no longer needed. + // (implementation of the TooltipClient method) + const String getTooltip(); - These properties are added without them being inside a named section. If you - want them to be kept together in a collapsible section, use addSection() instead. + /** A combination of these flags are used by setConnectedEdges(). */ - void addProperties (const Array & newPropertyComponents); - - /** Adds a set of properties to the panel. + enum ConnectedEdgeFlags + { + ConnectedOnLeft = 1, + ConnectedOnRight = 2, + ConnectedOnTop = 4, + ConnectedOnBottom = 8 + }; - These properties are added at the bottom of the list, under a section heading with - a plus/minus button that allows it to be opened and closed. + /** Hints about which edges of the button might be connected to adjoining buttons. - The components in the list will be owned by this object and will be automatically - deleted later on when no longer needed. + The value passed in is a bitwise combination of any of the values in the + ConnectedEdgeFlags enum. - To add properies without them being in a section, use addProperties(). + E.g. if you are placing two buttons adjacent to each other, you could use this to + indicate which edges are touching, and the LookAndFeel might choose to drawn them + without rounded corners on the edges that connect. It's only a hint, so the + LookAndFeel can choose to ignore it if it's not relevent for this type of + button. */ - void addSection (const String& sectionTitle, - const Array & newPropertyComponents, - const bool shouldSectionInitiallyBeOpen = true); + void setConnectedEdges (const int connectedEdgeFlags) throw(); - /** Calls the refresh() method of all PropertyComponents in the panel */ - void refreshAll() const; + /** Returns the set of flags passed into setConnectedEdges(). */ + int getConnectedEdgeFlags() const throw() { return connectedEdgeFlags; } - /** Returns a list of all the names of sections in the panel. + /** Indicates whether the button adjoins another one on its left edge. + @see setConnectedEdges + */ + bool isConnectedOnLeft() const throw() { return (connectedEdgeFlags & ConnectedOnLeft) != 0; } - These are the sections that have been added with addSection(). + /** Indicates whether the button adjoins another one on its right edge. + @see setConnectedEdges */ - const StringArray getSectionNames() const; + bool isConnectedOnRight() const throw() { return (connectedEdgeFlags & ConnectedOnRight) != 0; } - /** Returns true if the section at this index is currently open. + /** Indicates whether the button adjoins another one on its top edge. + @see setConnectedEdges + */ + bool isConnectedOnTop() const throw() { return (connectedEdgeFlags & ConnectedOnTop) != 0; } - The index is from 0 up to the number of items returned by getSectionNames(). + /** Indicates whether the button adjoins another one on its bottom edge. + @see setConnectedEdges */ - bool isSectionOpen (const int sectionIndex) const; + bool isConnectedOnBottom() const throw() { return (connectedEdgeFlags & ConnectedOnBottom) != 0; } - /** Opens or closes one of the sections. + /** Used by setState(). */ + enum ButtonState + { + buttonNormal, + buttonOver, + buttonDown + }; - The index is from 0 up to the number of items returned by getSectionNames(). - */ - void setSectionOpen (const int sectionIndex, const bool shouldBeOpen); + /** Can be used to force the button into a particular state. - /** Enables or disables one of the sections. + This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks + from happening. - The index is from 0 up to the number of items returned by getSectionNames(). + The state that you set here will only last until it is automatically changed when the mouse + enters or exits the button, or the mouse-button is pressed or released. */ - void setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled); + void setState (const ButtonState newState); - /** Saves the current state of open/closed sections so it can be restored later. + juce_UseDebuggingNewOperator - The caller is responsible for deleting the object that is returned. +protected: - To restore this state, use restoreOpennessState(). + /** This method is called when the button has been clicked. - @see restoreOpennessState + Subclasses can override this to perform whatever they actions they need + to do. + + Alternatively, a ButtonListener can be added to the button, and these listeners + will be called when the click occurs. + + @see triggerClick */ - XmlElement* getOpennessState() const; + virtual void clicked(); - /** Restores a previously saved arrangement of open/closed sections. + /** This method is called when the button has been clicked. - This will try to restore a snapshot of the panel's state that was created by - the getOpennessState() method. If any of the sections named in the original - XML aren't present, they will be ignored. + By default it just calls clicked(), but you might want to override it to handle + things like clicking when a modifier key is pressed, etc. - @see getOpennessState + @see ModifierKeys */ - void restoreOpennessState (const XmlElement& newState); + virtual void clicked (const ModifierKeys& modifiers); - /** Sets a message to be displayed when there are no properties in the panel. + /** Subclasses should override this to actually paint the button's contents. - The default message is "nothing selected". + It's better to use this than the paint method, because it gives you information + about the over/down state of the button. + + @param g the graphics context to use + @param isMouseOverButton true if the button is either in the 'over' or + 'down' state + @param isButtonDown true if the button should be drawn in the 'down' position */ - void setMessageWhenEmpty (const String& newMessage); + virtual void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown) = 0; - /** Returns the message that is displayed when there are no properties. - @see setMessageWhenEmpty + /** Called when the button's up/down/over state changes. + + Subclasses can override this if they need to do something special when the button + goes up or down. + + @see isDown, isOver */ - const String& getMessageWhenEmpty() const throw(); + virtual void buttonStateChanged(); + /** @internal */ + virtual void internalClickCallback (const ModifierKeys& modifiers); + /** @internal */ + void handleCommandMessage (int commandId); + /** @internal */ + void mouseEnter (const MouseEvent& e); + /** @internal */ + void mouseExit (const MouseEvent& e); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + bool keyPressed (const KeyPress& key, Component* originatingComponent); + /** @internal */ + bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); /** @internal */ void paint (Graphics& g); /** @internal */ - void resized(); - - juce_UseDebuggingNewOperator + void parentHierarchyChanged(); + /** @internal */ + void focusGained (FocusChangeType cause); + /** @internal */ + void focusLost (FocusChangeType cause); + /** @internal */ + void enablementChanged(); + /** @internal */ + void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&); + /** @internal */ + void applicationCommandListChanged(); private: - Viewport* viewport; - Component* propertyHolderComponent; - String messageWhenEmpty; - void updatePropHolderLayout() const; - void updatePropHolderLayout (const int width) const; -}; - -#endif // __JUCE_PROPERTYPANEL_JUCEHEADER__ -/********* End of inlined file: juce_PropertyPanel.h *********/ - -/** - A type of UI component that displays the parameters of an AudioProcessor as - a simple list of sliders. + Array shortcuts; + Component* keySource; + String text; + SortedSet buttonListeners; - This can be used for showing an editor for a processor that doesn't supply - its own custom editor. + friend class InternalButtonRepeatTimer; + Timer* repeatTimer; + uint32 buttonPressTime, lastTimeCallbackTime; + ApplicationCommandManager* commandManagerToUse; + int autoRepeatDelay, autoRepeatSpeed, autoRepeatMinimumDelay; + int radioGroupId, commandID, connectedEdgeFlags; + ButtonState buttonState; - @see AudioProcessor -*/ -class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor -{ -public: + bool isOn : 1; + bool clickTogglesState : 1; + bool needsToRelease : 1; + bool needsRepainting : 1; + bool isKeyDown : 1; + bool triggerOnMouseDown : 1; + bool generateTooltip : 1; - GenericAudioProcessorEditor (AudioProcessor* const owner); - ~GenericAudioProcessorEditor(); + void repeatTimerCallback() throw(); + Timer& getRepeatTimer() throw(); - void paint (Graphics& g); - void resized(); + ButtonState updateState (const MouseEvent* const e) throw(); + bool isShortcutPressed() const throw(); + void turnOffOtherButtonsInGroup (const bool sendChangeNotification); - juce_UseDebuggingNewOperator + void flashButtonState() throw(); + void sendClickMessage (const ModifierKeys& modifiers); + void sendStateMessage(); -private: - PropertyPanel* panel; + Button (const Button&); + const Button& operator= (const Button&); }; -#endif // __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ -/********* End of inlined file: juce_GenericAudioProcessorEditor.h *********/ - -#endif -#ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ +#endif // __JUCE_BUTTON_JUCEHEADER__ +/********* End of inlined file: juce_Button.h *********/ -/********* Start of inlined file: juce_AudioFormatReaderSource.h *********/ -#ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ -#define __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ +class ScrollBar; -/********* Start of inlined file: juce_PositionableAudioSource.h *********/ -#ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ +/** + A class for receiving events from a ScrollBar. -/********* Start of inlined file: juce_AudioSource.h *********/ -#ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ -#define __JUCE_AUDIOSOURCE_JUCEHEADER__ + You can register a ScrollBarListener with a ScrollBar using the ScrollBar::addListener() + method, and it will be called when the bar's position changes. -/** - Used by AudioSource::getNextAudioBlock(). + @see ScrollBar::addListener, ScrollBar::removeListener */ -struct JUCE_API AudioSourceChannelInfo +class JUCE_API ScrollBarListener { - /** The destination buffer to fill with audio data. - - When the AudioSource::getNextAudioBlock() method is called, the active section - of this buffer should be filled with whatever output the source produces. - - Only the samples specified by the startSample and numSamples members of this structure - should be affected by the call. +public: + /** Destructor. */ + virtual ~ScrollBarListener() {} - The contents of the buffer when it is passed to the the AudioSource::getNextAudioBlock() - method can be treated as the input if the source is performing some kind of filter operation, - but should be cleared if this is not the case - the clearActiveBufferRegion() is - a handy way of doing this. + /** Called when a ScrollBar is moved. - The number of channels in the buffer could be anything, so the AudioSource - must cope with this in whatever way is appropriate for its function. + @param scrollBarThatHasMoved the bar that has moved + @param newRangeStart the new range start of this bar */ - AudioSampleBuffer* buffer; + virtual void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, + const double newRangeStart) = 0; +}; - /** The first sample in the buffer from which the callback is expected - to write data. */ - int startSample; +/** + A scrollbar component. - /** The number of samples in the buffer which the callback is expected to - fill with data. */ - int numSamples; + To use a scrollbar, set up its total range using the setRangeLimits() method - this + sets the range of values it can represent. Then you can use setCurrentRange() to + change the position and size of the scrollbar's 'thumb'. - /** Convenient method to clear the buffer if the source is not producing any data. */ - void clearActiveBufferRegion() const - { - if (buffer != 0) - buffer->clear (startSample, numSamples); - } -}; + Registering a ScrollBarListener with the scrollbar will allow you to find out when + the user moves it, and you can use the getCurrentRangeStart() to find out where + they moved it to. -/** - Base class for objects that can produce a continuous stream of audio. + The scrollbar will adjust its own visibility according to whether its thumb size + allows it to actually be scrolled. - @see AudioFormatReaderSource, ResamplingAudioSource + For most purposes, it's probably easier to use a ViewportContainer or ListBox + instead of handling a scrollbar directly. + + @see ScrollBarListener */ -class JUCE_API AudioSource +class JUCE_API ScrollBar : public Component, + public AsyncUpdater, + private Timer { -protected: +public: - /** Creates an AudioSource. */ - AudioSource() throw() {} + /** Creates a Scrollbar. + + @param isVertical whether it should be a vertical or horizontal bar + @param buttonsAreVisible whether to show the up/down or left/right buttons + */ + ScrollBar (const bool isVertical, + const bool buttonsAreVisible = true); -public: /** Destructor. */ - virtual ~AudioSource() {} + ~ScrollBar(); - /** Tells the source to prepare for playing. + /** Returns true if the scrollbar is vertical, false if it's horizontal. */ + bool isVertical() const throw() { return vertical; } - The source can use this opportunity to initialise anything it needs to. + /** Changes the scrollbar's direction. - Note that this method could be called more than once in succession without - a matching call to releaseResources(), so make sure your code is robust and - can handle that kind of situation. + You'll also need to resize the bar appropriately - this just changes its internal + layout. - @param samplesPerBlockExpected the number of samples that the source - will be expected to supply each time its - getNextAudioBlock() method is called. This - number may vary slightly, because it will be dependent - on audio hardware callbacks, and these aren't - guaranteed to always use a constant block size, so - the source should be able to cope with small variations. - @param sampleRate the sample rate that the output will be used at - this - is needed by sources such as tone generators. - @see releaseResources, getNextAudioBlock + @param shouldBeVertical true makes it vertical; false makes it horizontal. */ - virtual void prepareToPlay (int samplesPerBlockExpected, - double sampleRate) = 0; - - /** Allows the source to release anything it no longer needs after playback has stopped. + void setOrientation (const bool shouldBeVertical) throw(); - This will be called when the source is no longer going to have its getNextAudioBlock() - method called, so it should release any spare memory, etc. that it might have - allocated during the prepareToPlay() call. + /** Shows or hides the scrollbar's buttons. */ + void setButtonVisibility (const bool buttonsAreVisible); - Note that there's no guarantee that prepareToPlay() will actually have been called before - releaseResources(), and it may be called more than once in succession, so make sure your - code is robust and doesn't make any assumptions about when it will be called. + /** Tells the scrollbar whether to make itself invisible when not needed. - @see prepareToPlay, getNextAudioBlock + The default behaviour is for a scrollbar to become invisible when the thumb + fills the whole of its range (i.e. when it can't be moved). Setting this + value to false forces the bar to always be visible. */ - virtual void releaseResources() = 0; + void setAutoHide (const bool shouldHideWhenFullRange); - /** Called repeatedly to fetch subsequent blocks of audio data. + /** Sets the minimum and maximum values that the bar will move between. - After calling the prepareToPlay() method, this callback will be made each - time the audio playback hardware (or whatever other destination the audio - data is going to) needs another block of data. + The bar's thumb will always be constrained so that the top of the thumb + will be >= minimum, and the bottom of the thumb <= maximum. - It will generally be called on a high-priority system thread, or possibly even - an interrupt, so be careful not to do too much work here, as that will cause - audio glitches! - - @see AudioSourceChannelInfo, prepareToPlay, releaseResources + @see setCurrentRange */ - virtual void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) = 0; -}; - -#endif // __JUCE_AUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_AudioSource.h *********/ - -/** - A type of AudioSource which can be repositioned. - - The basic AudioSource just streams continuously with no idea of a current - time or length, so the PositionableAudioSource is used for a finite stream - that has a current read position. - - @see AudioSource, AudioTransportSource -*/ -class JUCE_API PositionableAudioSource : public AudioSource -{ -protected: - - /** Creates the PositionableAudioSource. */ - PositionableAudioSource() throw() {} - -public: - /** Destructor */ - ~PositionableAudioSource() {} - - /** Tells the stream to move to a new position. + void setRangeLimits (const double minimum, + const double maximum) throw(); - Calling this indicates that the next call to AudioSource::getNextAudioBlock() - should return samples from this position. + /** Returns the lower value that the thumb can be set to. - Note that this may be called on a different thread to getNextAudioBlock(), - so the subclass should make sure it's synchronised. + This is the value set by setRangeLimits(). */ - virtual void setNextReadPosition (int newPosition) = 0; + double getMinimumRangeLimit() const throw() { return minimum; } - /** Returns the position from which the next block will be returned. + /** Returns the upper value that the thumb can be set to. - @see setNextReadPosition + This is the value set by setRangeLimits(). */ - virtual int getNextReadPosition() const = 0; + double getMaximumRangeLimit() const throw() { return maximum; } - /** Returns the total length of the stream (in samples). */ - virtual int getTotalLength() const = 0; + /** Changes the position of the scrollbar's 'thumb'. - /** Returns true if this source is actually playing in a loop. */ - virtual bool isLooping() const = 0; -}; + This sets both the position and size of the thumb - to just set the position without + changing the size, you can use setCurrentRangeStart(). -#endif // __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_PositionableAudioSource.h *********/ + If this method call actually changes the scrollbar's position, it will trigger an + asynchronous call to ScrollBarListener::scrollBarMoved() for all the listeners that + are registered. -/********* Start of inlined file: juce_AudioFormatReader.h *********/ -#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ -#define __JUCE_AUDIOFORMATREADER_JUCEHEADER__ + @param newStart the top (or left) of the thumb, in the range + getMinimumRangeLimit() <= newStart <= getMaximumRangeLimit(). If the + value is beyond these limits, it will be clipped. + @param newSize the size of the thumb, such that + getMinimumRangeLimit() <= newStart + newSize <= getMaximumRangeLimit(). If the + size is beyond these limits, it will be clipped. + @see setCurrentRangeStart, getCurrentRangeStart, getCurrentRangeSize + */ + void setCurrentRange (double newStart, + double newSize) throw(); -class AudioFormat; + /** Moves the bar's thumb position. -/** - Reads samples from an audio file stream. + This will move the thumb position without changing the thumb size. Note + that the maximum thumb start position is (getMaximumRangeLimit() - getCurrentRangeSize()). - A subclass that reads a specific type of audio format will be created by - an AudioFormat object. + If this method call actually changes the scrollbar's position, it will trigger an + asynchronous call to ScrollBarListener::scrollBarMoved() for all the listeners that + are registered. - @see AudioFormat, AudioFormatWriter -*/ -class JUCE_API AudioFormatReader -{ -protected: + @see setCurrentRange + */ + void setCurrentRangeStart (double newStart) throw(); - /** Creates an AudioFormatReader object. + /** Returns the position of the top of the thumb. - @param sourceStream the stream to read from - this will be deleted - by this object when it is no longer needed. (Some - specialised readers might not use this parameter and - can leave it as 0). - @param formatName the description that will be returned by the getFormatName() - method + @see setCurrentRangeStart */ - AudioFormatReader (InputStream* const sourceStream, - const String& formatName); - -public: - /** Destructor. */ - virtual ~AudioFormatReader(); + double getCurrentRangeStart() const throw() { return rangeStart; } - /** Returns a description of what type of format this is. + /** Returns the current size of the thumb. - E.g. "AIFF" + @see setCurrentRange */ - const String getFormatName() const throw() { return formatName; } + double getCurrentRangeSize() const throw() { return rangeSize; } - /** Reads samples from the stream. + /** Sets the amount by which the up and down buttons will move the bar. - @param destSamples an array of buffers into which the sample data for each - channel will be written. - If the format is fixed-point, each channel will be written - as an array of 32-bit signed integers using the full - range -0x80000000 to 0x7fffffff, regardless of the source's - bit-depth. If it is a floating-point format, you should cast - the resulting array to a (float**) to get the values (in the - range -1.0 to 1.0 or beyond) - If the format is stereo, then destSamples[0] is the left channel - data, and destSamples[1] is the right channel. - The numDestChannels parameter indicates how many pointers this array - contains, but some of these pointers can be null if you don't want to - read data for some of the channels - @param numDestChannels the number of array elements in the destChannels array - @param startSampleInSource the position in the audio file or stream at which the samples - should be read, as a number of samples from the start of the - stream. It's ok for this to be beyond the start or end of the - available data - any samples that are out-of-range will be returned - as zeros. - @param numSamplesToRead the number of samples to read. If this is greater than the number - of samples that the file or stream contains. the result will be padded - with zeros - @param fillLeftoverChannelsWithCopies if true, this indicates that if there's no source data available - for some of the channels that you pass in, then they should be filled with - copies of valid source channels. - E.g. if you're reading a mono file and you pass 2 channels to this method, then - if fillLeftoverChannelsWithCopies is true, both destination channels will be filled - with the same data from the file's single channel. If fillLeftoverChannelsWithCopies - was false, then only the first channel would be filled with the file's contents, and - the second would be cleared. If there are many channels, e.g. you try to read 4 channels - from a stereo file, then the last 3 would all end up with copies of the same data. - @returns true if the operation succeeded, false if there was an error. Note - that reading sections of data beyond the extent of the stream isn't an - error - the reader should just return zeros for these regions - @see readMaxLevels + The value here is in terms of the total range, and is added or subtracted + from the thumb position when the user clicks an up/down (or left/right) button. */ - bool read (int** destSamples, - int numDestChannels, - int64 startSampleInSource, - int numSamplesToRead, - const bool fillLeftoverChannelsWithCopies); + void setSingleStepSize (const double newSingleStepSize) throw(); - /** Finds the highest and lowest sample levels from a section of the audio stream. + /** Moves the scrollbar by a number of single-steps. - This will read a block of samples from the stream, and measure the - highest and lowest sample levels from the channels in that section, returning - these as normalised floating-point levels. + This will move the bar by a multiple of its single-step interval (as + specified using the setSingleStepSize() method). - @param startSample the offset into the audio stream to start reading from. It's - ok for this to be beyond the start or end of the stream. - @param numSamples how many samples to read - @param lowestLeft on return, this is the lowest absolute sample from the left channel - @param highestLeft on return, this is the highest absolute sample from the left channel - @param lowestRight on return, this is the lowest absolute sample from the right - channel (if there is one) - @param highestRight on return, this is the highest absolute sample from the right - channel (if there is one) - @see read + A positive value here will move the bar down or to the right, a negative + value moves it up or to the left. */ - virtual void readMaxLevels (int64 startSample, - int64 numSamples, - float& lowestLeft, - float& highestLeft, - float& lowestRight, - float& highestRight); + void moveScrollbarInSteps (const int howManySteps) throw(); - /** Scans the source looking for a sample whose magnitude is in a specified range. + /** Moves the scroll bar up or down in pages. - This will read from the source, either forwards or backwards between two sample - positions, until it finds a sample whose magnitude lies between two specified levels. + This will move the bar by a multiple of its current thumb size, effectively + doing a page-up or down. - If it finds a suitable sample, it returns its position; if not, it will return -1. + A positive value here will move the bar down or to the right, a negative + value moves it up or to the left. + */ + void moveScrollbarInPages (const int howManyPages) throw(); - There's also a minimumConsecutiveSamples setting to help avoid spikes or zero-crossing - points when you're searching for a continuous range of samples + /** Scrolls to the top (or left). - @param startSample the first sample to look at - @param numSamplesToSearch the number of samples to scan. If this value is negative, - the search will go backwards - @param magnitudeRangeMinimum the lowest magnitude (inclusive) that is considered a hit, from 0 to 1.0 - @param magnitudeRangeMaximum the highest magnitude (inclusive) that is considered a hit, from 0 to 1.0 - @param minimumConsecutiveSamples if this is > 0, the method will only look for a sequence - of this many consecutive samples, all of which lie - within the target range. When it finds such a sequence, - it returns the position of the first in-range sample - it found (i.e. the earliest one if scanning forwards, the - latest one if scanning backwards) + This is the same as calling setCurrentRangeStart (getMinimumRangeLimit()); */ - int64 searchForLevel (int64 startSample, - int64 numSamplesToSearch, - const double magnitudeRangeMinimum, - const double magnitudeRangeMaximum, - const int minimumConsecutiveSamples); + void scrollToTop() throw(); - /** The sample-rate of the stream. */ - double sampleRate; + /** Scrolls to the bottom (or right). - /** The number of bits per sample, e.g. 16, 24, 32. */ - unsigned int bitsPerSample; + This is the same as calling setCurrentRangeStart (getMaximumRangeLimit() - getCurrentRangeSize()); + */ + void scrollToBottom() throw(); - /** The total number of samples in the audio stream. */ - int64 lengthInSamples; + /** Changes the delay before the up and down buttons autorepeat when they are held + down. - /** The total number of channels in the audio stream. */ - unsigned int numChannels; + For an explanation of what the parameters are for, see Button::setRepeatSpeed(). - /** Indicates whether the data is floating-point or fixed. */ - bool usesFloatingPointData; + @see Button::setRepeatSpeed + */ + void setButtonRepeatSpeed (const int initialDelayInMillisecs, + const int repeatDelayInMillisecs, + const int minimumDelayInMillisecs = -1) throw(); - /** A set of metadata values that the reader has pulled out of the stream. + /** A set of colour IDs to use to change the colour of various aspects of the component. - Exactly what these values are depends on the format, so you can - check out the format implementation code to see what kind of stuff - they understand. - */ - StringPairArray metadataValues; + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - /** The input stream, for use by subclasses. */ - InputStream* input; + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1000300, /**< The background colour of the scrollbar. */ + thumbColourId = 0x1000400, /**< A base colour to use for the thumb. The look and feel will probably use variations on this colour. */ + trackColourId = 0x1000401 /**< A base colour to use for the slot area of the bar. The look and feel will probably use variations on this colour. */ + }; - /** Subclasses must implement this method to perform the low-level read operation. + /** Registers a listener that will be called when the scrollbar is moved. */ + void addListener (ScrollBarListener* const listener) throw(); - Callers should use read() instead of calling this directly. + /** Deregisters a previously-registered listener. */ + void removeListener (ScrollBarListener* const listener) throw(); - @param destSamples the array of destination buffers to fill. Some of these - pointers may be null - @param numDestChannels the number of items in the destSamples array. This - value is guaranteed not to be greater than the number of - channels that this reader object contains - @param startOffsetInDestBuffer the number of samples from the start of the - dest data at which to begin writing - @param startSampleInFile the number of samples into the source data at which - to begin reading. This value is guaranteed to be >= 0. - @param numSamples the number of samples to read - */ - virtual bool readSamples (int** destSamples, - int numDestChannels, - int startOffsetInDestBuffer, - int64 startSampleInFile, - int numSamples) = 0; + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + void handleAsyncUpdate(); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); juce_UseDebuggingNewOperator private: - String formatName; - AudioFormatReader (const AudioFormatReader&); - const AudioFormatReader& operator= (const AudioFormatReader&); + double minimum, maximum; + double rangeStart, rangeSize; + double singleStepSize, dragStartRange; + int thumbAreaStart, thumbAreaSize, thumbStart, thumbSize; + int dragStartMousePos, lastMousePos; + int initialDelayInMillisecs, repeatDelayInMillisecs, minimumDelayInMillisecs; + bool vertical, isDraggingThumb, alwaysVisible; + Button* upButton; + Button* downButton; + SortedSet listeners; + + void updateThumbPosition() throw(); + void timerCallback(); + + ScrollBar (const ScrollBar&); + const ScrollBar& operator= (const ScrollBar&); }; -#endif // __JUCE_AUDIOFORMATREADER_JUCEHEADER__ -/********* End of inlined file: juce_AudioFormatReader.h *********/ +#endif // __JUCE_SCROLLBAR_JUCEHEADER__ +/********* End of inlined file: juce_ScrollBar.h *********/ /** - A type of AudioSource that will read from an AudioFormatReader. + A Viewport is used to contain a larger child component, and allows the child + to be automatically scrolled around. + + To use a Viewport, just create one and set the component that goes inside it + using the setViewedComponent() method. When the child component changes size, + the Viewport will adjust its scrollbars accordingly. + + A subclass of the viewport can be created which will receive calls to its + visibleAreaChanged() method when the subcomponent changes position or size. - @see PositionableAudioSource, AudioTransportSource, BufferingAudioSource */ -class JUCE_API AudioFormatReaderSource : public PositionableAudioSource +class JUCE_API Viewport : public Component, + private ComponentListener, + private ScrollBarListener { public: - /** Creates an AudioFormatReaderSource for a given reader. + /** Creates a Viewport. - @param sourceReader the reader to use as the data source - @param deleteReaderWhenThisIsDeleted if true, the reader passed-in will be deleted - when this object is deleted; if false it will be - left up to the caller to manage its lifetime + The viewport is initially empty - use the setViewedComponent() method to + add a child component for it to manage. */ - AudioFormatReaderSource (AudioFormatReader* const sourceReader, - const bool deleteReaderWhenThisIsDeleted); + Viewport (const String& componentName = String::empty); /** Destructor. */ - ~AudioFormatReaderSource(); + ~Viewport(); - /** Toggles loop-mode. + /** Sets the component that this viewport will contain and scroll around. - If set to true, it will continuously loop the input source. If false, - it will just emit silence after the source has finished. + This will add the given component to this Viewport and position it at + (0, 0). - @see isLooping - */ - void setLooping (const bool shouldLoop) throw(); + (Don't add or remove any child components directly using the normal + Component::addChildComponent() methods). - /** Returns whether loop-mode is turned on or not. */ - bool isLooping() const { return looping; } + @param newViewedComponent the component to add to this viewport (this pointer + may be null). The component passed in will be deleted + by the Viewport when it's no longer needed + @see getViewedComponent + */ + void setViewedComponent (Component* const newViewedComponent); - /** Returns the reader that's being used. */ - AudioFormatReader* getAudioFormatReader() const throw() { return reader; } + /** Returns the component that's currently being used inside the Viewport. - /** Implementation of the AudioSource method. */ - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + @see setViewedComponent + */ + Component* getViewedComponent() const throw() { return contentComp; } - /** Implementation of the AudioSource method. */ - void releaseResources(); + /** Changes the position of the viewed component. - /** Implementation of the AudioSource method. */ - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + The inner component will be moved so that the pixel at the top left of + the viewport will be the pixel at position (xPixelsOffset, yPixelsOffset) + within the inner component. - /** Implements the PositionableAudioSource method. */ - void setNextReadPosition (int newPosition); + This will update the scrollbars and might cause a call to visibleAreaChanged(). - /** Implements the PositionableAudioSource method. */ - int getNextReadPosition() const; + @see getViewPositionX, getViewPositionY, setViewPositionProportionately + */ + void setViewPosition (const int xPixelsOffset, + const int yPixelsOffset); - /** Implements the PositionableAudioSource method. */ - int getTotalLength() const; + /** Changes the view position as a proportion of the distance it can move. - juce_UseDebuggingNewOperator + The values here are from 0.0 to 1.0 - where (0, 0) would put the + visible area in the top-left, and (1, 1) would put it as far down and + to the right as it's possible to go whilst keeping the child component + on-screen. + */ + void setViewPositionProportionately (const double proportionX, + const double proportionY); -private: - AudioFormatReader* reader; - bool deleteReader; + /** If the specified position is at the edges of the viewport, this method scrolls + the viewport to bring that position nearer to the centre. - int volatile nextPlayPos; - bool volatile looping; + Call this if you're dragging an object inside a viewport and want to make it scroll + when the user approaches an edge. You might also find Component::beginDragAutoRepeat() + useful when auto-scrolling. - void readBufferSection (int start, int length, AudioSampleBuffer& buffer, int startSample); + @param mouseX the x position, relative to the Viewport's top-left + @param mouseY the y position, relative to the Viewport's top-left + @param distanceFromEdge specifies how close to an edge the position needs to be + before the viewport should scroll in that direction + @param maximumSpeed the maximum number of pixels that the viewport is allowed + to scroll by. + @returns true if the viewport was scrolled + */ + bool autoScroll (int mouseX, int mouseY, int distanceFromEdge, int maximumSpeed); - AudioFormatReaderSource (const AudioFormatReaderSource&); - const AudioFormatReaderSource& operator= (const AudioFormatReaderSource&); -}; + /** Returns the position within the child component of the top-left of its visible area. + @see getViewWidth, setViewPosition + */ + int getViewPositionX() const throw() { return lastVX; } -#endif // __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_AudioFormatReaderSource.h *********/ + /** Returns the position within the child component of the top-left of its visible area. + @see getViewHeight, setViewPosition + */ + int getViewPositionY() const throw() { return lastVY; } -#endif -#ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ + /** Returns the width of the visible area of the child component. -#endif -#ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ + This may be less than the width of this Viewport if there's a vertical scrollbar + or if the child component is itself smaller. + */ + int getViewWidth() const throw() { return lastVW; } -/********* Start of inlined file: juce_AudioSourcePlayer.h *********/ -#ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ -#define __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ + /** Returns the height of the visible area of the child component. -/** - Wrapper class to continuously stream audio from an audio source to an - AudioIODevice. + This may be less than the height of this Viewport if there's a horizontal scrollbar + or if the child component is itself smaller. + */ + int getViewHeight() const throw() { return lastVH; } - This object acts as an AudioIODeviceCallback, so can be attached to an - output device, and will stream audio from an AudioSource. -*/ -class JUCE_API AudioSourcePlayer : public AudioIODeviceCallback -{ -public: + /** Returns the width available within this component for the contents. - /** Creates an empty AudioSourcePlayer. */ - AudioSourcePlayer(); + This will be the width of the viewport component minus the width of a + vertical scrollbar (if visible). + */ + int getMaximumVisibleWidth() const throw(); - /** Destructor. + /** Returns the height available within this component for the contents. - Make sure this object isn't still being used by an AudioIODevice before - deleting it! + This will be the height of the viewport component minus the space taken up + by a horizontal scrollbar (if visible). */ - virtual ~AudioSourcePlayer(); + int getMaximumVisibleHeight() const throw(); - /** Changes the current audio source to play from. + /** Callback method that is called when the visible area changes. - If the source passed in is already being used, this method will do nothing. - If the source is not null, its prepareToPlay() method will be called - before it starts being used for playback. + This will be called when the visible area is moved either be scrolling or + by calls to setViewPosition(), etc. + */ + virtual void visibleAreaChanged (int visibleX, int visibleY, + int visibleW, int visibleH); - If there's another source currently playing, its releaseResources() method - will be called after it has been swapped for the new one. + /** Turns scrollbars on or off. - @param newSource the new source to use - this will NOT be deleted - by this object when no longer needed, so it's the - caller's responsibility to manage it. + If set to false, the scrollbars won't ever appear. When true (the default) + they will appear only when needed. */ - void setSource (AudioSource* newSource); + void setScrollBarsShown (const bool showVerticalScrollbarIfNeeded, + const bool showHorizontalScrollbarIfNeeded); - /** Returns the source that's playing. + /** True if the vertical scrollbar is enabled. + @see setScrollBarsShown + */ + bool isVerticalScrollBarShown() const throw() { return showVScrollbar; } - May return 0 if there's no source. + /** True if the horizontal scrollbar is enabled. + @see setScrollBarsShown */ - AudioSource* getCurrentSource() const throw() { return source; } + bool isHorizontalScrollBarShown() const throw() { return showHScrollbar; } - /** Sets a gain to apply to the audio data. */ - void setGain (const float newGain) throw(); + /** Changes the width of the scrollbars. - /** Implementation of the AudioIODeviceCallback method. */ - void audioDeviceIOCallback (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples); + If this isn't specified, the default width from the LookAndFeel class will be used. - /** Implementation of the AudioIODeviceCallback method. */ - void audioDeviceAboutToStart (AudioIODevice* device); + @see LookAndFeel::getDefaultScrollbarWidth + */ + void setScrollBarThickness (const int thickness); - /** Implementation of the AudioIODeviceCallback method. */ - void audioDeviceStopped(); + /** Returns the thickness of the scrollbars. - juce_UseDebuggingNewOperator + @see setScrollBarThickness + */ + int getScrollBarThickness() const throw(); -private: + /** Changes the distance that a single-step click on a scrollbar button + will move the viewport. + */ + void setSingleStepSizes (const int stepX, const int stepY); - CriticalSection readLock; - AudioSource* source; - double sampleRate; - int bufferSize; - float* channels [128]; - float* outputChans [128]; - const float* inputChans [128]; - AudioSampleBuffer tempBuffer; - float lastGain, gain; + /** Shows or hides the buttons on any scrollbars that are used. - AudioSourcePlayer (const AudioSourcePlayer&); - const AudioSourcePlayer& operator= (const AudioSourcePlayer&); -}; + @see ScrollBar::setButtonVisibility + */ + void setScrollBarButtonVisibility (const bool buttonsVisible); -#endif // __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ -/********* End of inlined file: juce_AudioSourcePlayer.h *********/ + /** Returns a pointer to the scrollbar component being used. -#endif -#ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ + Handy if you need to customise the bar somehow. + */ + ScrollBar* getVerticalScrollBar() const throw() { return verticalScrollBar; } -/********* Start of inlined file: juce_AudioTransportSource.h *********/ -#ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ -#define __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ + /** Returns a pointer to the scrollbar component being used. -/********* Start of inlined file: juce_BufferingAudioSource.h *********/ -#ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ + Handy if you need to customise the bar somehow. + */ + ScrollBar* getHorizontalScrollBar() const throw() { return horizontalScrollBar; } -/** - An AudioSource which takes another source as input, and buffers it using a thread. + juce_UseDebuggingNewOperator - Create this as a wrapper around another thread, and it will read-ahead with - a background thread to smooth out playback. You can either create one of these - directly, or use it indirectly using an AudioTransportSource. + /** @internal */ + void resized(); + /** @internal */ + void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); + /** @internal */ + bool useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - @see PositionableAudioSource, AudioTransportSource +private: + Component* contentComp; + int lastVX, lastVY, lastVW, lastVH; + int scrollBarThickness; + int singleStepX, singleStepY; + bool showHScrollbar, showVScrollbar; + Component* contentHolder; + ScrollBar* verticalScrollBar; + ScrollBar* horizontalScrollBar; + + void updateVisibleRegion(); + Viewport (const Viewport&); + const Viewport& operator= (const Viewport&); +}; + +#endif // __JUCE_VIEWPORT_JUCEHEADER__ +/********* End of inlined file: juce_Viewport.h *********/ + +/********* Start of inlined file: juce_PopupMenu.h *********/ +#ifndef __JUCE_POPUPMENU_JUCEHEADER__ +#define __JUCE_POPUPMENU_JUCEHEADER__ + +/********* Start of inlined file: juce_PopupMenuCustomComponent.h *********/ +#ifndef __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ +#define __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ + +/** A user-defined copmonent that can appear inside one of the rows of a popup menu. + + @see PopupMenu::addCustomItem */ -class JUCE_API BufferingAudioSource : public PositionableAudioSource +class JUCE_API PopupMenuCustomComponent : public Component { public: + /** Destructor. */ + ~PopupMenuCustomComponent(); - /** Creates a BufferingAudioSource. + /** Chooses the size that this component would like to have. - @param source the input source to read from - @param deleteSourceWhenDeleted if true, then the input source object will - be deleted when this object is deleted - @param numberOfSamplesToBuffer the size of buffer to use for reading ahead + Note that the size which this method returns isn't necessarily the one that + the menu will give it, as it will be stretched to fit the other items in + the menu. */ - BufferingAudioSource (PositionableAudioSource* source, - const bool deleteSourceWhenDeleted, - int numberOfSamplesToBuffer); + virtual void getIdealSize (int& idealWidth, + int& idealHeight) = 0; - /** Destructor. + /** Dismisses the menu indicating that this item has been chosen. - The input source may be deleted depending on whether the deleteSourceWhenDeleted - flag was set in the constructor. + This will cause the menu to exit from its modal state, returning + this item's id as the result. */ - ~BufferingAudioSource(); + void triggerMenuItem(); - /** Implementation of the AudioSource method. */ - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + /** Returns true if this item should be highlighted because the mouse is + over it. - /** Implementation of the AudioSource method. */ - void releaseResources(); + You can call this method in your paint() method to find out whether + to draw a highlight. + */ + bool isItemHighlighted() const throw() { return isHighlighted; } - /** Implementation of the AudioSource method. */ - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); +protected: + /** Constructor. - /** Implements the PositionableAudioSource method. */ - void setNextReadPosition (int newPosition); + If isTriggeredAutomatically is true, then the menu will automatically detect + a click on this component and use that to trigger it. If it's false, then it's + up to your class to manually trigger the item if it wants to. + */ + PopupMenuCustomComponent (const bool isTriggeredAutomatically = true); - /** Implements the PositionableAudioSource method. */ - int getNextReadPosition() const; +private: + friend class MenuItemInfo; + friend class MenuItemComponent; + friend class PopupMenuWindow; + int refCount_; + bool isHighlighted, isTriggeredAutomatically; - /** Implements the PositionableAudioSource method. */ - int getTotalLength() const { return source->getTotalLength(); } + PopupMenuCustomComponent (const PopupMenuCustomComponent&); + const PopupMenuCustomComponent& operator= (const PopupMenuCustomComponent&); +}; - /** Implements the PositionableAudioSource method. */ - bool isLooping() const { return source->isLooping(); } +#endif // __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_PopupMenuCustomComponent.h *********/ - juce_UseDebuggingNewOperator +/** Creates and displays a popup-menu. -private: + To show a popup-menu, you create one of these, add some items to it, then + call its show() method, which returns the id of the item the user selects. - PositionableAudioSource* source; - bool deleteSourceWhenDeleted; - int numberOfSamplesToBuffer; - AudioSampleBuffer buffer; - CriticalSection bufferStartPosLock; - int volatile bufferValidStart, bufferValidEnd, nextPlayPos; - bool wasSourceLooping; - double volatile sampleRate; + E.g. @code + void MyWidget::mouseDown (const MouseEvent& e) + { + PopupMenu m; + m.addItem (1, "item 1"); + m.addItem (2, "item 2"); - friend class SharedBufferingAudioSourceThread; - bool readNextBufferChunk(); - void readBufferSection (int start, int length, int bufferOffset); + const int result = m.show(); - BufferingAudioSource (const BufferingAudioSource&); - const BufferingAudioSource& operator= (const BufferingAudioSource&); -}; + if (result == 0) + { + // user dismissed the menu without picking anything + } + else if (result == 1) + { + // user picked item 1 + } + else if (result == 2) + { + // user picked item 2 + } + } + @endcode -#endif // __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_BufferingAudioSource.h *********/ + Submenus are easy too: @code -/********* Start of inlined file: juce_ResamplingAudioSource.h *********/ -#ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ + void MyWidget::mouseDown (const MouseEvent& e) + { + PopupMenu subMenu; + subMenu.addItem (1, "item 1"); + subMenu.addItem (2, "item 2"); -/** - A type of AudioSource that takes an input source and changes its sample rate. + PopupMenu mainMenu; + mainMenu.addItem (3, "item 3"); + mainMenu.addSubMenu ("other choices", subMenu); - @see AudioSource + const int result = m.show(); + + ...etc + } + @endcode */ -class JUCE_API ResamplingAudioSource : public AudioSource +class JUCE_API PopupMenu { public: - /** Creates a ResamplingAudioSource for a given input source. + /** Creates an empty popup menu. */ + PopupMenu() throw(); - @param inputSource the input source to read from - @param deleteInputWhenDeleted if true, the input source will be deleted when - this object is deleted - */ - ResamplingAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted); + /** Creates a copy of another menu. */ + PopupMenu (const PopupMenu& other) throw(); /** Destructor. */ - ~ResamplingAudioSource(); + ~PopupMenu() throw(); - /** Changes the resampling ratio. + /** Copies this menu from another one. */ + const PopupMenu& operator= (const PopupMenu& other) throw(); - (This value can be changed at any time, even while the source is running). + /** Resets the menu, removing all its items. */ + void clear() throw(); - @param samplesInPerOutputSample if set to 1.0, the input is passed through; higher - values will speed it up; lower values will slow it - down. The ratio must be greater than 0 - */ - void setResamplingRatio (const double samplesInPerOutputSample); + /** Appends a new text item for this menu to show. - /** Returns the current resampling ratio. + @param itemResultId the number that will be returned from the show() method + if the user picks this item. The value should never be + zero, because that's used to indicate that the user didn't + select anything. + @param itemText the text to show. + @param isActive if false, the item will be shown 'greyed-out' and can't be + picked + @param isTicked if true, the item will be shown with a tick next to it + @param iconToUse if this is non-zero, it should be an image that will be + displayed to the left of the item. This method will take its + own copy of the image passed-in, so there's no need to keep + it hanging around. - This is the value that was set by setResamplingRatio(). + @see addSeparator, addColouredItem, addCustomItem, addSubMenu */ - double getResamplingRatio() const throw() { return ratio; } + void addItem (const int itemResultId, + const String& itemText, + const bool isActive = true, + const bool isTicked = false, + const Image* const iconToUse = 0) throw(); - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - void releaseResources(); - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + /** Adds an item that represents one of the commands in a command manager object. - juce_UseDebuggingNewOperator + @param commandManager the manager to use to trigger the command and get information + about it + @param commandID the ID of the command + @param displayName if this is non-empty, then this string will be used instead of + the command's registered name + */ + void addCommandItem (ApplicationCommandManager* commandManager, + const int commandID, + const String& displayName = String::empty) throw(); -private: - AudioSource* const input; - const bool deleteInputWhenDeleted; - double ratio, lastRatio; - AudioSampleBuffer buffer; - int bufferPos, sampsInBuffer; - double subSampleOffset; - double coefficients[6]; - CriticalSection ratioLock; + /** Appends a text item with a special colour. - void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); - void createLowPass (const double proportionalRate); + This is the same as addItem(), but specifies a colour to use for the + text, which will override the default colours that are used by the + current look-and-feel. See addItem() for a description of the parameters. + */ + void addColouredItem (const int itemResultId, + const String& itemText, + const Colour& itemTextColour, + const bool isActive = true, + const bool isTicked = false, + const Image* const iconToUse = 0) throw(); - struct FilterState - { - double x1, x2, y1, y2; - }; + /** Appends a custom menu item. - FilterState filterStates[2]; - void resetFilters(); + This will add a user-defined component to use as a menu item. The component + passed in will be deleted by this menu when it's no longer needed. - void applyFilter (float* samples, int num, FilterState& fs); + @see PopupMenuCustomComponent + */ + void addCustomItem (const int itemResultId, + PopupMenuCustomComponent* const customComponent) throw(); - ResamplingAudioSource (const ResamplingAudioSource&); - const ResamplingAudioSource& operator= (const ResamplingAudioSource&); -}; + /** Appends a custom menu item that can't be used to trigger a result. -#endif // __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_ResamplingAudioSource.h *********/ + This will add a user-defined component to use as a menu item. Unlike the + addCustomItem() method that takes a PopupMenuCustomComponent, this version + can't trigger a result from it, so doesn't take a menu ID. It also doesn't + delete the component when it's finished, so it's the caller's responsibility + to manage the component that is passed-in. -/** - An AudioSource that takes a PositionableAudioSource and allows it to be - played, stopped, started, etc. + if triggerMenuItemAutomaticallyWhenClicked is true, the menu itself will handle + detection of a mouse-click on your component, and use that to trigger the + menu ID specified in itemResultId. If this is false, the menu item can't + be triggered, so itemResultId is not used. - This can also be told use a buffer and background thread to read ahead, and - if can correct for different sample-rates. + @see PopupMenuCustomComponent + */ + void addCustomItem (const int itemResultId, + Component* customComponent, + int idealWidth, int idealHeight, + const bool triggerMenuItemAutomaticallyWhenClicked) throw(); - You may want to use one of these along with an AudioSourcePlayer and AudioIODevice - to control playback of an audio file. + /** Appends a sub-menu. - @see AudioSource, AudioSourcePlayer -*/ -class JUCE_API AudioTransportSource : public PositionableAudioSource, - public ChangeBroadcaster -{ -public: + If the menu that's passed in is empty, it will appear as an inactive item. + */ + void addSubMenu (const String& subMenuName, + const PopupMenu& subMenu, + const bool isActive = true, + Image* const iconToUse = 0, + const bool isTicked = false) throw(); - /** Creates an AudioTransportSource. + /** Appends a separator to the menu, to help break it up into sections. - After creating one of these, use the setSource() method to select an input source. + The menu class is smart enough not to display separators at the top or bottom + of the menu, and it will replace mutliple adjacent separators with a single + one, so your code can be quite free and easy about adding these, and it'll + always look ok. */ - AudioTransportSource(); - - /** Destructor. */ - ~AudioTransportSource(); + void addSeparator() throw(); - /** Sets the reader that is being used as the input source. + /** Adds a non-clickable text item to the menu. - This will stop playback, reset the position to 0 and change to the new reader. + This is a bold-font items which can be used as a header to separate the items + into named groups. + */ + void addSectionHeader (const String& title) throw(); - The source passed in will not be deleted by this object, so must be managed by - the caller. + /** Returns the number of items that the menu currently contains. - @param newSource the new input source to use. This may be zero - @param readAheadBufferSize a size of buffer to use for reading ahead. If this - is zero, no reading ahead will be done; if it's - greater than zero, a BufferingAudioSource will be used - to do the reading-ahead - @param sourceSampleRateToCorrectFor if this is non-zero, it specifies the sample - rate of the source, and playback will be sample-rate - adjusted to maintain playback at the correct pitch. If - this is 0, no sample-rate adjustment will be performed + (This doesn't count separators). */ - void setSource (PositionableAudioSource* const newSource, - int readAheadBufferSize = 0, - double sourceSampleRateToCorrectFor = 0.0); + int getNumItems() const throw(); - /** Changes the current playback position in the source stream. + /** Returns true if the menu contains a command item that triggers the given command. */ + bool containsCommandItem (const int commandID) const throw(); - The next time the getNextAudioBlock() method is called, this - is the time from which it'll read data. + /** Returns true if the menu contains any items that can be used. */ + bool containsAnyActiveItems() const throw(); - @see getPosition - */ - void setPosition (double newPosition); + /** Displays the menu and waits for the user to pick something. - /** Returns the position that the next data block will be read from + This will display the menu modally, and return the ID of the item that the + user picks. If they click somewhere off the menu to get rid of it without + choosing anything, this will return 0. - This is a time in seconds. - */ - double getCurrentPosition() const; + The current location of the mouse will be used as the position to show the + menu - to explicitly set the menu's position, use showAt() instead. Depending + on where this point is on the screen, the menu will appear above, below or + to the side of the point. - /** Returns true if the player has stopped because its input stream ran out of data. + @param itemIdThatMustBeVisible if you set this to the ID of one of the menu items, + then when the menu first appears, it will make sure + that this item is visible. So if the menu has too many + items to fit on the screen, it will be scrolled to a + position where this item is visible. + @param minimumWidth a minimum width for the menu, in pixels. It may be wider + than this if some items are too long to fit. + @param maximumNumColumns if there are too many items to fit on-screen in a single + vertical column, the menu may be laid out as a series of + columns - this is the maximum number allowed. To use the + default value for this (probably about 7), you can pass + in zero. + @param standardItemHeight if this is non-zero, it will be used as the standard + height for menu items (apart from custom items) + @see showAt */ - bool hasStreamFinished() const throw() { return inputStreamEOF; } + int show (const int itemIdThatMustBeVisible = 0, + const int minimumWidth = 0, + const int maximumNumColumns = 0, + const int standardItemHeight = 0); - /** Starts playing (if a source has been selected). + /** Displays the menu at a specific location. - If it starts playing, this will send a message to any ChangeListeners - that are registered with this object. - */ - void start(); + This is the same as show(), but uses a specific location (in global screen + co-ordinates) rather than the current mouse position. - /** Stops playing. + Note that the co-ordinates don't specify the top-left of the menu - they + indicate a point of interest, and the menu will position itself nearby to + this point, trying to keep it fully on-screen. - If it's actually playing, this will send a message to any ChangeListeners - that are registered with this object. + @see show() */ - void stop(); - - /** Returns true if it's currently playing. */ - bool isPlaying() const throw() { return playing; } + int showAt (const int screenX, + const int screenY, + const int itemIdThatMustBeVisible = 0, + const int minimumWidth = 0, + const int maximumNumColumns = 0, + const int standardItemHeight = 0); - /** Changes the gain to apply to the output. + /** Displays the menu as if it's attached to a component such as a button. - @param newGain a factor by which to multiply the outgoing samples, - so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc. + This is similar to showAt(), but will position it next to the given component, e.g. + so that the menu's edge is aligned with that of the component. This is intended for + things like buttons that trigger a pop-up menu. */ - void setGain (const float newGain) throw(); + int showAt (Component* componentToAttachTo, + const int itemIdThatMustBeVisible = 0, + const int minimumWidth = 0, + const int maximumNumColumns = 0, + const int standardItemHeight = 0); - /** Returns the current gain setting. + /** Closes any menus that are currently open. - @see setGain + This might be useful if you have a situation where your window is being closed + by some means other than a user action, and you'd like to make sure that menus + aren't left hanging around. */ - float getGain() const throw() { return gain; } + static void JUCE_CALLTYPE dismissAllActiveMenus() throw(); - /** Implementation of the AudioSource method. */ - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + /** Specifies a look-and-feel for the menu and any sub-menus that it has. - /** Implementation of the AudioSource method. */ - void releaseResources(); + This can be called before show() if you need a customised menu. Be careful + not to delete the LookAndFeel object before the menu has been deleted. + */ + void setLookAndFeel (LookAndFeel* const newLookAndFeel) throw(); - /** Implementation of the AudioSource method. */ - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + /** A set of colour IDs to use to change the colour of various aspects of the menu. - /** Implements the PositionableAudioSource method. */ - void setNextReadPosition (int newPosition); + These constants can be used either via the LookAndFeel::setColour() + method for the look and feel that is set for this menu with setLookAndFeel() - /** Implements the PositionableAudioSource method. */ - int getNextReadPosition() const; + @see setLookAndFeel, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1000700, /**< The colour to fill the menu's background with. */ + textColourId = 0x1000600, /**< The colour for normal menu item text, (unless the + colour is specified when the item is added). */ + headerTextColourId = 0x1000601, /**< The colour for section header item text (see the + addSectionHeader() method). */ + highlightedBackgroundColourId = 0x1000900, /**< The colour to fill the background of the currently + highlighted menu item. */ + highlightedTextColourId = 0x1000800, /**< The colour to use for the text of the currently + highlighted item. */ + }; - /** Implements the PositionableAudioSource method. */ - int getTotalLength() const; + /** + Allows you to iterate through the items in a pop-up menu, and examine + their properties. - /** Implements the PositionableAudioSource method. */ - bool isLooping() const; + To use this, just create one and repeatedly call its next() method. When this + returns true, all the member variables of the iterator are filled-out with + information describing the menu item. When it returns false, the end of the + list has been reached. + */ + class JUCE_API MenuItemIterator + { + public: + + /** Creates an iterator that will scan through the items in the specified + menu. + + Be careful not to add any items to a menu while it is being iterated, + or things could get out of step. + */ + MenuItemIterator (const PopupMenu& menu) throw(); + + /** Destructor. */ + ~MenuItemIterator() throw(); + + /** Returns true if there is another item, and sets up all this object's + member variables to reflect that item's properties. + */ + bool next() throw(); + + String itemName; + const PopupMenu* subMenu; + int itemId; + bool isSeparator; + bool isTicked; + bool isEnabled; + bool isCustomComponent; + bool isSectionHeader; + const Colour* customColour; + const Image* customImage; + ApplicationCommandManager* commandManager; + + juce_UseDebuggingNewOperator + + private: + const PopupMenu& menu; + int index; + + MenuItemIterator (const MenuItemIterator&); + const MenuItemIterator& operator= (const MenuItemIterator&); + }; juce_UseDebuggingNewOperator private: - PositionableAudioSource* source; - ResamplingAudioSource* resamplerSource; - BufferingAudioSource* bufferingSource; - PositionableAudioSource* positionableSource; - AudioSource* masterSource; + friend class PopupMenuWindow; + friend class MenuItemIterator; + VoidArray items; + LookAndFeel* lookAndFeel; + bool separatorPending; - CriticalSection callbackLock; - float volatile gain, lastGain; - bool volatile playing, stopped; - double sampleRate, sourceSampleRate; - int blockSize, readAheadBufferSize; - bool isPrepared, inputStreamEOF; + void addSeparatorIfPending(); - AudioTransportSource (const AudioTransportSource&); - const AudioTransportSource& operator= (const AudioTransportSource&); + int showMenu (const int x, const int y, const int w, const int h, + const int itemIdThatMustBeVisible, + const int minimumWidth, + const int maximumNumColumns, + const int standardItemHeight, + const bool alignToRectangle, + Component* const componentAttachedTo) throw(); + + friend class MenuBarComponent; + Component* createMenuComponent (const int x, const int y, const int w, const int h, + const int itemIdThatMustBeVisible, + const int minimumWidth, + const int maximumNumColumns, + const int standardItemHeight, + const bool alignToRectangle, + Component* menuBarComponent, + ApplicationCommandManager** managerOfChosenCommand, + Component* const componentAttachedTo) throw(); }; -#endif // __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_AudioTransportSource.h *********/ +#endif // __JUCE_POPUPMENU_JUCEHEADER__ +/********* End of inlined file: juce_PopupMenu.h *********/ -#endif -#ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ +class TextEditor; +class TextHolderComponent; -#endif -#ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ +/** + Receives callbacks from a TextEditor component when it changes. -/********* Start of inlined file: juce_ChannelRemappingAudioSource.h *********/ -#ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ + @see TextEditor::addListener +*/ +class JUCE_API TextEditorListener +{ +public: + /** Destructor. */ + virtual ~TextEditorListener() {} -/** - An AudioSource that takes the audio from another source, and re-maps its - input and output channels to a different arrangement. + /** Called when the user changes the text in some way. */ + virtual void textEditorTextChanged (TextEditor& editor) = 0; - You can use this to increase or decrease the number of channels that an - audio source uses, or to re-order those channels. + /** Called when the user presses the return key. */ + virtual void textEditorReturnKeyPressed (TextEditor& editor) = 0; - Call the reset() method before using it to set up a default mapping, and then - the setInputChannelMapping() and setOutputChannelMapping() methods to - create an appropriate mapping, otherwise no channels will be connected and - it'll produce silence. + /** Called when the user presses the escape key. */ + virtual void textEditorEscapeKeyPressed (TextEditor& editor) = 0; - @see AudioSource + /** Called when the text editor loses focus. */ + virtual void textEditorFocusLost (TextEditor& editor) = 0; +}; + +/** + A component containing text that can be edited. + + A TextEditor can either be in single- or multi-line mode, and supports mixed + fonts and colours. + + @see TextEditorListener, Label */ -class ChannelRemappingAudioSource : public AudioSource +class JUCE_API TextEditor : public Component, + public SettableTooltipClient { public: - /** Creates a remapping source that will pass on audio from the given input. + /** Creates a new, empty text editor. - @param source the input source to use. Make sure that this doesn't - get deleted before the ChannelRemappingAudioSource object - @param deleteSourceWhenDeleted if true, the input source will be deleted - when this object is deleted, if false, the caller is - responsible for its deletion + @param componentName the name to pass to the component for it to use as its name + @param passwordCharacter if this is not zero, this character will be used as a replacement + for all characters that are drawn on screen - e.g. to create + a password-style textbox containing circular blobs instead of text, + you could set this value to 0x25cf, which is the unicode character + for a black splodge (not all fonts include this, though), or 0x2022, + which is a bullet (probably the best choice for linux). */ - ChannelRemappingAudioSource (AudioSource* const source, - const bool deleteSourceWhenDeleted); + TextEditor (const String& componentName = String::empty, + const tchar passwordCharacter = 0); /** Destructor. */ - ~ChannelRemappingAudioSource(); + virtual ~TextEditor(); - /** Specifies a number of channels that this audio source must produce from its - getNextAudioBlock() callback. - */ - void setNumberOfChannelsToProduce (const int requiredNumberOfChannels) throw(); + /** Puts the editor into either multi- or single-line mode. - /** Clears any mapped channels. + By default, the editor will be in single-line mode, so use this if you need a multi-line + editor. - After this, no channels are mapped, so this object will produce silence. Create - some mappings with setInputChannelMapping() and setOutputChannelMapping(). + See also the setReturnKeyStartsNewLine() method, which will also need to be turned + on if you want a multi-line editor with line-breaks. + + @see isMultiLine, setReturnKeyStartsNewLine */ - void clearAllMappings() throw(); + void setMultiLine (const bool shouldBeMultiLine, + const bool shouldWordWrap = true); - /** Creates an input channel mapping. + /** Returns true if the editor is in multi-line mode. + */ + bool isMultiLine() const throw(); - When the getNextAudioBlock() method is called, the data in channel sourceChannelIndex of the incoming - data will be sent to destChannelIndex of our input source. + /** Changes the behaviour of the return key. - @param destChannelIndex the index of an input channel in our input audio source (i.e. the - source specified when this object was created). - @param sourceChannelIndex the index of the input channel in the incoming audio data buffer - during our getNextAudioBlock() callback + If set to true, the return key will insert a new-line into the text; if false + it will trigger a call to the TextEditorListener::textEditorReturnKeyPressed() + method. By default this is set to false, and when true it will only insert + new-lines when in multi-line mode (see setMultiLine()). */ - void setInputChannelMapping (const int destChannelIndex, - const int sourceChannelIndex) throw(); - - /** Creates an output channel mapping. + void setReturnKeyStartsNewLine (const bool shouldStartNewLine); - When the getNextAudioBlock() method is called, the data returned in channel sourceChannelIndex by - our input audio source will be copied to channel destChannelIndex of the final buffer. + /** Returns the value set by setReturnKeyStartsNewLine(). - @param sourceChannelIndex the index of an output channel coming from our input audio source - (i.e. the source specified when this object was created). - @param destChannelIndex the index of the output channel in the incoming audio data buffer - during our getNextAudioBlock() callback + See setReturnKeyStartsNewLine() for more info. */ - void setOutputChannelMapping (const int sourceChannelIndex, - const int destChannelIndex) throw(); + bool getReturnKeyStartsNewLine() const throw() { return returnKeyStartsNewLine; } - /** Returns the channel from our input that will be sent to channel inputChannelIndex of - our input audio source. + /** Indicates whether the tab key should be accepted and used to input a tab character, + or whether it gets ignored. + + By default the tab key is ignored, so that it can be used to switch keyboard focus + between components. */ - int getRemappedInputChannel (const int inputChannelIndex) const throw(); + void setTabKeyUsedAsCharacter (const bool shouldTabKeyBeUsed) throw(); - /** Returns the output channel to which channel outputChannelIndex of our input audio - source will be sent to. + /** Returns true if the tab key is being used for input. + @see setTabKeyUsedAsCharacter */ - int getRemappedOutputChannel (const int outputChannelIndex) const throw(); + bool isTabKeyUsedAsCharacter() const throw() { return tabKeyUsed; } - /** Returns an XML object to encapsulate the state of the mappings. + /** Changes the editor to read-only mode. - @see restoreFromXml - */ - XmlElement* createXml() const throw(); + By default, the text editor is not read-only. If you're making it read-only, you + might also want to call setCaretVisible (false) to get rid of the caret. - /** Restores the mappings from an XML object created by createXML(). + The text can still be highlighted and copied when in read-only mode. - @see createXml + @see isReadOnly, setCaretVisible */ - void restoreFromXml (const XmlElement& e) throw(); + void setReadOnly (const bool shouldBeReadOnly); - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - void releaseResources(); - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + /** Returns true if the editor is in read-only mode. + */ + bool isReadOnly() const throw(); - juce_UseDebuggingNewOperator + /** Makes the caret visible or invisible. -private: - int requiredNumberOfChannels; - Array remappedInputs, remappedOutputs; + By default the caret is visible. - AudioSource* const source; - const bool deleteSourceWhenDeleted; + @see setCaretColour, setCaretPosition + */ + void setCaretVisible (const bool shouldBeVisible) throw(); - AudioSampleBuffer buffer; - AudioSourceChannelInfo remappedInfo; + /** Returns true if the caret is enabled. + @see setCaretVisible + */ + bool isCaretVisible() const throw() { return caretVisible; } - CriticalSection lock; + /** Enables/disables a vertical scrollbar. - ChannelRemappingAudioSource (const ChannelRemappingAudioSource&); - const ChannelRemappingAudioSource& operator= (const ChannelRemappingAudioSource&); -}; + (This only applies when in multi-line mode). When the text gets too long to fit + in the component, a scrollbar can appear to allow it to be scrolled. Even when + this is enabled, the scrollbar will be hidden unless it's needed. -#endif // __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_ChannelRemappingAudioSource.h *********/ + By default the scrollbar is enabled. + */ + void setScrollbarsShown (bool shouldBeEnabled) throw(); -#endif -#ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ + /** Returns true if scrollbars are enabled. + @see setScrollbarsShown + */ + bool areScrollbarsShown() const throw() { return scrollbarVisible; } -/********* Start of inlined file: juce_IIRFilterAudioSource.h *********/ -#ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ + /** Changes the password character used to disguise the text. -/** - An AudioSource that performs an IIR filter on another source. -*/ -class JUCE_API IIRFilterAudioSource : public AudioSource -{ -public: + @param passwordCharacter if this is not zero, this character will be used as a replacement + for all characters that are drawn on screen - e.g. to create + a password-style textbox containing circular blobs instead of text, + you could set this value to 0x25cf, which is the unicode character + for a black splodge (not all fonts include this, though), or 0x2022, + which is a bullet (probably the best choice for linux). + */ + void setPasswordCharacter (const tchar passwordCharacter) throw(); - /** Creates a IIRFilterAudioSource for a given input source. + /** Returns the current password character. + @see setPasswordCharacter +l */ + tchar getPasswordCharacter() const throw() { return passwordCharacter; } - @param inputSource the input source to read from - @param deleteInputWhenDeleted if true, the input source will be deleted when - this object is deleted - */ - IIRFilterAudioSource (AudioSource* const inputSource, - const bool deleteInputWhenDeleted); + /** Allows a right-click menu to appear for the editor. - /** Destructor. */ - ~IIRFilterAudioSource(); + (This defaults to being enabled). - /** Changes the filter to use the same parameters as the one being passed in. + If enabled, right-clicking (or command-clicking on the Mac) will pop up a menu + of options such as cut/copy/paste, undo/redo, etc. */ - void setFilterParameters (const IIRFilter& newSettings); + void setPopupMenuEnabled (const bool menuEnabled) throw(); - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); - void releaseResources(); - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + /** Returns true if the right-click menu is enabled. + @see setPopupMenuEnabled + */ + bool isPopupMenuEnabled() const throw() { return popupMenuEnabled; } - juce_UseDebuggingNewOperator + /** Returns true if a popup-menu is currently being displayed. + */ + bool isPopupMenuCurrentlyActive() const throw() { return menuActive; } -private: + /** A set of colour IDs to use to change the colour of various aspects of the editor. - AudioSource* const input; - const bool deleteInputWhenDeleted; - OwnedArray iirFilters; + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - IIRFilterAudioSource (const IIRFilterAudioSource&); - const IIRFilterAudioSource& operator= (const IIRFilterAudioSource&); -}; + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1000200, /**< The colour to use for the text component's background - this can be + transparent if necessary. */ -#endif // __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_IIRFilterAudioSource.h *********/ + textColourId = 0x1000201, /**< The colour that will be used when text is added to the editor. Note + that because the editor can contain multiple colours, calling this + method won't change the colour of existing text - to do that, call + applyFontToAllText() after calling this method.*/ -#endif -#ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ + highlightColourId = 0x1000202, /**< The colour with which to fill the background of highlighted sections of + the text - this can be transparent if you don't want to show any + highlighting.*/ -/********* Start of inlined file: juce_MixerAudioSource.h *********/ -#ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ + highlightedTextColourId = 0x1000203, /**< The colour with which to draw the text in highlighted sections. */ -/** - An AudioSource that mixes together the output of a set of other AudioSources. + caretColourId = 0x1000204, /**< The colour with which to draw the caret. */ - Input sources can be added and removed while the mixer is running as long as their - prepareToPlay() and releaseResources() methods are called before and after adding - them to the mixer. -*/ -class JUCE_API MixerAudioSource : public AudioSource -{ -public: + outlineColourId = 0x1000205, /**< If this is non-transparent, it will be used to draw a box around + the edge of the component. */ - /** Creates a MixerAudioSource. - */ - MixerAudioSource(); + focusedOutlineColourId = 0x1000206, /**< If this is non-transparent, it will be used to draw a box around + the edge of the component when it has focus. */ - /** Destructor. */ - ~MixerAudioSource(); + shadowColourId = 0x1000207, /**< If this is non-transparent, it'll be used to draw an inner shadow + around the edge of the editor. */ + }; - /** Adds an input source to the mixer. + /** Sets the font to use for newly added text. - If the mixer is running you'll need to make sure that the input source - is ready to play by calling its prepareToPlay() method before adding it. - If the mixer is stopped, then its input sources will be automatically - prepared when the mixer's prepareToPlay() method is called. + This will change the font that will be used next time any text is added or entered + into the editor. It won't change the font of any existing text - to do that, use + applyFontToAllText() instead. - @param newInput the source to add to the mixer - @param deleteWhenRemoved if true, then this source will be deleted when - the mixer is deleted or when removeAllInputs() is - called (unless the source is previously removed - with the removeInputSource method) + @see applyFontToAllText */ - void addInputSource (AudioSource* newInput, - const bool deleteWhenRemoved); + void setFont (const Font& newFont) throw(); - /** Removes an input source. + /** Applies a font to all the text in the editor. - If the mixer is running, this will remove the source but not call its - releaseResources() method, so the caller might want to do this manually. + This will also set the current font to use for any new text that's added. - @param input the source to remove - @param deleteSource whether to delete this source after it's been removed + @see setFont */ - void removeInputSource (AudioSource* input, - const bool deleteSource); - - /** Removes all the input sources. + void applyFontToAllText (const Font& newFont); - If the mixer is running, this will remove the sources but not call their - releaseResources() method, so the caller might want to do this manually. + /** Returns the font that's currently being used for new text. - Any sources which were added with the deleteWhenRemoved flag set will be - deleted by this method. + @see setFont */ - void removeAllInputs(); + const Font getFont() const throw(); - /** Implementation of the AudioSource method. + /** If set to true, focusing on the editor will highlight all its text. - This will call prepareToPlay() on all its input sources. + (Set to false by default). + + This is useful for boxes where you expect the user to re-enter all the + text when they focus on the component, rather than editing what's already there. */ - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + void setSelectAllWhenFocused (const bool b) throw(); - /** Implementation of the AudioSource method. + /** Sets limits on the characters that can be entered. - This will call releaseResources() on all its input sources. + @param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no + limit is set + @param allowedCharacters if this is non-empty, then only characters that occur in + this string are allowed to be entered into the editor. */ - void releaseResources(); + void setInputRestrictions (const int maxTextLength, + const String& allowedCharacters = String::empty) throw(); - /** Implementation of the AudioSource method. */ - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + /** When the text editor is empty, it can be set to display a message. - juce_UseDebuggingNewOperator + This is handy for things like telling the user what to type in the box - the + string is only displayed, it's not taken to actually be the contents of + the editor. + */ + void setTextToShowWhenEmpty (const String& text, const Colour& colourToUse) throw(); -private: + /** Changes the size of the scrollbars that are used. - VoidArray inputs; - BitArray inputsToDelete; - CriticalSection lock; - AudioSampleBuffer tempBuffer; - double currentSampleRate; - int bufferSizeExpected; + Handy if you need smaller scrollbars for a small text box. + */ + void setScrollBarThickness (const int newThicknessPixels); - MixerAudioSource (const MixerAudioSource&); - const MixerAudioSource& operator= (const MixerAudioSource&); -}; + /** Shows or hides the buttons on any scrollbars that are used. -#endif // __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_MixerAudioSource.h *********/ + @see ScrollBar::setButtonVisibility + */ + void setScrollBarButtonVisibility (const bool buttonsVisible); -#endif -#ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ + /** Registers a listener to be told when things happen to the text. -#endif -#ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ + @see removeListener + */ + void addListener (TextEditorListener* const newListener) throw(); -#endif -#ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ + /** Deregisters a listener. -/********* Start of inlined file: juce_ToneGeneratorAudioSource.h *********/ -#ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ -#define __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ + @see addListener + */ + void removeListener (TextEditorListener* const listenerToRemove) throw(); -/** - A simple AudioSource that generates a sine wave. + /** Returns the entire contents of the editor. */ + const String getText() const throw(); -*/ -class JUCE_API ToneGeneratorAudioSource : public AudioSource -{ -public: + /** Returns a section of the contents of the editor. */ + const String getTextSubstring (const int startCharacter, const int endCharacter) const throw(); - /** Creates a ToneGeneratorAudioSource. */ - ToneGeneratorAudioSource(); + /** Returns true if there are no characters in the editor. - /** Destructor. */ - ~ToneGeneratorAudioSource(); + This is more efficient than calling getText().isEmpty(). + */ + bool isEmpty() const throw(); - /** Sets the signal's amplitude. */ - void setAmplitude (const float newAmplitude); + /** Sets the entire content of the editor. - /** Sets the signal's frequency. */ - void setFrequency (const double newFrequencyHz); + This will clear the editor and insert the given text (using the current text colour + and font). You can set the current text colour using + @code setColour (TextEditor::textColourId, ...); + @endcode - /** Implementation of the AudioSource method. */ - void prepareToPlay (int samplesPerBlockExpected, double sampleRate); + @param newText the text to add + @param sendTextChangeMessage if true, this will cause a change message to + be sent to all the listeners. + @see insertText + */ + void setText (const String& newText, + const bool sendTextChangeMessage = true); - /** Implementation of the AudioSource method. */ - void releaseResources(); + /** Inserts some text at the current cursor position. - /** Implementation of the AudioSource method. */ - void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); + If a section of the text is highlighted, it will be replaced by + this string, otherwise it will be inserted. - juce_UseDebuggingNewOperator + To delete a section of text, you can use setHighlightedRegion() to + highlight it, and call insertTextAtCursor (String::empty). -private: + @see setCaretPosition, getCaretPosition, setHighlightedRegion + */ + void insertTextAtCursor (String textToInsert); - double frequency, sampleRate; - double currentPhase, phasePerSample; - float amplitude; + /** Deletes all the text from the editor. */ + void clear(); - ToneGeneratorAudioSource (const ToneGeneratorAudioSource&); - const ToneGeneratorAudioSource& operator= (const ToneGeneratorAudioSource&); -}; + /** Deletes the currently selected region, and puts it on the clipboard. -#endif // __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ -/********* End of inlined file: juce_ToneGeneratorAudioSource.h *********/ + @see copy, paste, SystemClipboard + */ + void cut(); -#endif -#ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ + /** Copies any currently selected region to the clipboard. -/********* Start of inlined file: juce_AudioDeviceManager.h *********/ -#ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ -#define __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ + @see cut, paste, SystemClipboard + */ + void copy(); -/********* Start of inlined file: juce_AudioIODeviceType.h *********/ -#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ -#define __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ + /** Pastes the contents of the clipboard into the editor at the cursor position. -class AudioDeviceManager; -class Component; + @see cut, copy, SystemClipboard + */ + void paste(); -/** - Represents a type of audio driver, such as DirectSound, ASIO, CoreAudio, etc. + /** Moves the caret to be in front of a given character. - To get a list of available audio driver types, use the createDeviceTypes() - method. Each of the objects returned can then be used to list the available - devices of that type. E.g. - @code - OwnedArray types; - AudioIODeviceType::createDeviceTypes (types); + @see getCaretPosition + */ + void setCaretPosition (const int newIndex) throw(); - for (int i = 0; i < types.size(); ++i) - { - String typeName (types[i]->getTypeName()); // This will be things like "DirectSound", "CoreAudio", etc. + /** Returns the current index of the caret. - types[i]->scanForDevices(); // This must be called before getting the list of devices + @see setCaretPosition + */ + int getCaretPosition() const throw(); - StringArray deviceNames (types[i]->getDeviceNames()); // This will now return a list of available devices of this type + /** Attempts to scroll the text editor so that the caret ends up at + a specified position. - for (int j = 0; j < deviceNames.size(); ++j) - { - AudioIODevice* device = types[i]->createDevice (deviceNames [j]); + This won't affect the caret's position within the text, it tries to scroll + the entire editor vertically and horizontally so that the caret is sitting + at the given position (relative to the top-left of this component). - ... - } - } - @endcode + Depending on the amount of text available, it might not be possible to + scroll far enough for the caret to reach this exact position, but it + will go as far as it can in that direction. + */ + void scrollEditorToPositionCaret (const int desiredCaretX, + const int desiredCaretY) throw(); - For an easier way of managing audio devices and their settings, have a look at the - AudioDeviceManager class. + /** Get the graphical position of the caret. - @see AudioIODevice, AudioDeviceManager -*/ -class JUCE_API AudioIODeviceType -{ -public: + The rectangle returned is relative to the component's top-left corner. + @see scrollEditorToPositionCaret + */ + const Rectangle getCaretRectangle() throw(); - /** Returns the name of this type of driver that this object manages. + /** Selects a section of the text. + */ + void setHighlightedRegion (int startIndex, + int numberOfCharactersToHighlight) throw(); - This will be something like "DirectSound", "ASIO", "CoreAudio", "ALSA", etc. + /** Returns the first character that is selected. + + If nothing is selected, this will still return a character index, but getHighlightedRegionLength() + will return 0. + + @see setHighlightedRegion, getHighlightedRegionLength */ - const String& getTypeName() const throw() { return typeName; } + int getHighlightedRegionStart() const throw() { return selectionStart; } - /** Refreshes the object's cached list of known devices. + /** Returns the number of characters that are selected. - This must be called at least once before calling getDeviceNames() or any of - the other device creation methods. + @see setHighlightedRegion, getHighlightedRegionStart */ - virtual void scanForDevices() = 0; + int getHighlightedRegionLength() const throw() { return jmax (0, selectionEnd - selectionStart); } - /** Returns the list of available devices of this type. + /** Returns the section of text that is currently selected. */ + const String getHighlightedText() const throw(); - The scanForDevices() method must have been called to create this list. + /** Finds the index of the character at a given position. - @param wantInputNames only really used by DirectSound where devices are split up - into inputs and outputs, this indicates whether to use - the input or output name to refer to a pair of devices. + The co-ordinates are relative to the component's top-left. */ - virtual const StringArray getDeviceNames (const bool wantInputNames = false) const = 0; - - /** Returns the name of the default device. + int getTextIndexAt (const int x, const int y) throw(); - This will be one of the names from the getDeviceNames() list. + /** Counts the number of characters in the text. - @param forInput if true, this means that a default input device should be - returned; if false, it should return the default output + This is quicker than getting the text as a string if you just need to know + the length. */ - virtual int getDefaultDeviceIndex (const bool forInput) const = 0; + int getTotalNumChars() throw(); - /** Returns the index of a given device in the list of device names. - If asInput is true, it shows the index in the inputs list, otherwise it - looks for it in the outputs list. + /** Returns the total width of the text, as it is currently laid-out. + + This may be larger than the size of the TextEditor, and can change when + the TextEditor is resized or the text changes. */ - virtual int getIndexOfDevice (AudioIODevice* device, const bool asInput) const = 0; + int getTextWidth() const throw(); - /** Returns true if two different devices can be used for the input and output. + /** Returns the maximum height of the text, as it is currently laid-out. + + This may be larger than the size of the TextEditor, and can change when + the TextEditor is resized or the text changes. */ - virtual bool hasSeparateInputsAndOutputs() const = 0; + int getTextHeight() const throw(); - /** Creates one of the devices of this type. + /** Changes the size of the gap at the top and left-edge of the editor. - The deviceName must be one of the strings returned by getDeviceNames(), and - scanForDevices() must have been called before this method is used. + By default there's a gap of 4 pixels. */ - virtual AudioIODevice* createDevice (const String& outputDeviceName, - const String& inputDeviceName) = 0; + void setIndents (const int newLeftIndent, const int newTopIndent) throw(); - struct DeviceSetupDetails - { - AudioDeviceManager* manager; - int minNumInputChannels, maxNumInputChannels; - int minNumOutputChannels, maxNumOutputChannels; - bool useStereoPairs; - }; + /** Changes the size of border left around the edge of the component. - /** Destructor. */ - virtual ~AudioIODeviceType(); + @see getBorder + */ + void setBorder (const BorderSize& border) throw(); -protected: - AudioIODeviceType (const tchar* const typeName); + /** Returns the size of border around the edge of the component. -private: - String typeName; + @see setBorder + */ + const BorderSize getBorder() const throw(); - AudioIODeviceType (const AudioIODeviceType&); - const AudioIODeviceType& operator= (const AudioIODeviceType&); -}; + /** Used to disable the auto-scrolling which keeps the cursor visible. -#endif // __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ -/********* End of inlined file: juce_AudioIODeviceType.h *********/ + If true (the default), the editor will scroll when the cursor moves offscreen. If + set to false, it won't. + */ + void setScrollToShowCursor (const bool shouldScrollToShowCursor) throw(); -/********* Start of inlined file: juce_MidiOutput.h *********/ -#ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ -#define __JUCE_MIDIOUTPUT_JUCEHEADER__ + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void paintOverChildren (Graphics& g); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseDoubleClick (const MouseEvent& e); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + bool keyStateChanged (const bool isKeyDown); + /** @internal */ + void focusGained (FocusChangeType cause); + /** @internal */ + void focusLost (FocusChangeType cause); + /** @internal */ + void resized(); + /** @internal */ + void enablementChanged(); + /** @internal */ + void colourChanged(); -/** - Represents a midi output device. + juce_UseDebuggingNewOperator - To create one of these, use the static getDevices() method to find out what - outputs are available, then use the openDevice() method to try to open one. +protected: - @see MidiInput -*/ -class JUCE_API MidiOutput : private Thread -{ -public: + /** This adds the items to the popup menu. - /** Returns a list of the available midi output devices. + By default it adds the cut/copy/paste items, but you can override this if + you need to replace these with your own items. - You can open one of the devices by passing its index into the - openDevice() method. + If you want to add your own items to the existing ones, you can override this, + call the base class's addPopupMenuItems() method, then append your own items. - @see getDefaultDeviceIndex, openDevice - */ - static const StringArray getDevices(); + When the menu has been shown, performPopupMenuAction() will be called to + perform the item that the user has chosen. - /** Returns the index of the default midi output device to use. + The default menu items will be added using item IDs in the range + 0x7fff0000 - 0x7fff1000, so you should avoid those values for your own + menu IDs. - This refers to the index in the list returned by getDevices(). + If this was triggered by a mouse-click, the mouseClickEvent parameter will be + a pointer to the info about it, or may be null if the menu is being triggered + by some other means. + + @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled */ - static int getDefaultDeviceIndex(); + virtual void addPopupMenuItems (PopupMenu& menuToAddTo, + const MouseEvent* mouseClickEvent); - /** Tries to open one of the midi output devices. + /** This is called to perform one of the items that was shown on the popup menu. - This will return a MidiOutput object if it manages to open it. You can then - send messages to this device, and delete it when no longer needed. + If you've overridden addPopupMenuItems(), you should also override this + to perform the actions that you've added. - If the device can't be opened, this will return a null pointer. + If you've overridden addPopupMenuItems() but have still left the default items + on the menu, remember to call the superclass's performPopupMenuAction() + so that it can perform the default actions if that's what the user clicked on. - @param deviceIndex the index of a device from the list returned by getDevices() - @see getDevices + @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled */ - static MidiOutput* openDevice (int deviceIndex); + virtual void performPopupMenuAction (const int menuItemID); -#if JUCE_LINUX || JUCE_MAC || DOXYGEN - /** This will try to create a new midi output device (Not available on Windows). + /** Scrolls the minimum distance needed to get the caret into view. */ + void scrollToMakeSureCursorIsVisible() throw(); - This will attempt to create a new midi output device that other apps can connect - to and use as their midi input. + /** @internal */ + void moveCaret (int newCaretPos) throw(); - Returns 0 if a device can't be created. + /** @internal */ + void moveCursorTo (const int newPosition, const bool isSelecting) throw(); - @param deviceName the name to use for the new device + /** Used internally to dispatch a text-change message. */ + void textChanged() throw(); + + /** Begins a new transaction in the UndoManager. */ - static MidiOutput* createNewDevice (const String& deviceName); -#endif + void newTransaction() throw(); - /** Destructor. */ - virtual ~MidiOutput(); + /** Used internally to trigger an undo or redo. */ + void doUndoRedo (const bool isRedo); - /** Makes this device output a midi message. + /** Can be overridden to intercept return key presses directly */ + virtual void returnPressed(); - @see MidiMessage - */ - virtual void sendMessageNow (const MidiMessage& message); + /** Can be overridden to intercept escape key presses directly */ + virtual void escapePressed(); - /** Sends a midi reset to the device. */ - virtual void reset(); + /** @internal */ + void handleCommandMessage (int commandId); - /** Returns the current volume setting for this device. */ - virtual bool getVolume (float& leftVol, - float& rightVol); +private: - /** Changes the overall volume for this device. */ - virtual void setVolume (float leftVol, - float rightVol); + Viewport* viewport; + TextHolderComponent* textHolder; + BorderSize borderSize; - /** This lets you supply a block of messages that will be sent out at some point - in the future. + bool readOnly : 1; + bool multiline : 1; + bool wordWrap : 1; + bool returnKeyStartsNewLine : 1; + bool caretVisible : 1; + bool popupMenuEnabled : 1; + bool selectAllTextWhenFocused : 1; + bool scrollbarVisible : 1; + bool wasFocused : 1; + bool caretFlashState : 1; + bool keepCursorOnScreen : 1; + bool tabKeyUsed : 1; + bool menuActive : 1; - The MidiOutput class has an internal thread that can send out timestamped - messages - this appends a set of messages to its internal buffer, ready for - sending. + UndoManager undoManager; + float cursorX, cursorY, cursorHeight; + int maxTextLength; + int selectionStart, selectionEnd; + int leftIndent, topIndent; + unsigned int lastTransactionTime; + Font currentFont; + int totalNumChars, caretPosition; + VoidArray sections; + String textToShowWhenEmpty; + Colour colourForTextWhenEmpty; + tchar passwordCharacter; - This will only work if you've already started the thread with startBackgroundThread(). + enum + { + notDragging, + draggingSelectionStart, + draggingSelectionEnd + } dragType; - A time is supplied, at which the block of messages should be sent. This time uses - the same time base as Time::getMillisecondCounter(), and must be in the future. + String allowedCharacters; + SortedSet listeners; - The samplesPerSecondForBuffer parameter indicates the number of samples per second - used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the - samplesPerSecondForBuffer value is needed to convert this sample position to a - real time. - */ - virtual void sendBlockOfMessages (const MidiBuffer& buffer, - const double millisecondCounterToStartAt, - double samplesPerSecondForBuffer) throw(); + friend class TextEditorInsertAction; + friend class TextEditorRemoveAction; - /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). - */ - virtual void clearAllPendingMessages() throw(); + void coalesceSimilarSections() throw(); + void splitSection (const int sectionIndex, const int charToSplitAt) throw(); - /** Starts up a background thread so that the device can send blocks of data. + void clearInternal (UndoManager* const um) throw(); - Call this to get the device ready, before using sendBlockOfMessages(). - */ - virtual void startBackgroundThread() throw(); + void insert (const String& text, + const int insertIndex, + const Font& font, + const Colour& colour, + UndoManager* const um, + const int caretPositionToMoveTo) throw(); - /** Stops the background thread, and clears any pending midi events. + void reinsert (const int insertIndex, + const VoidArray& sections) throw(); - @see startBackgroundThread - */ - virtual void stopBackgroundThread() throw(); + void remove (const int startIndex, + int endIndex, + UndoManager* const um, + const int caretPositionToMoveTo) throw(); - juce_UseDebuggingNewOperator + void getCharPosition (const int index, + float& x, float& y, + float& lineHeight) const throw(); -protected: - void* internal; + void updateCaretPosition() throw(); - struct PendingMessage - { - PendingMessage (const uint8* const data, const int len, const double sampleNumber) throw(); + int indexAtPosition (const float x, + const float y) throw(); - MidiMessage message; - PendingMessage* next; + int findWordBreakAfter (const int position) const throw(); + int findWordBreakBefore (const int position) const throw(); - juce_UseDebuggingNewOperator - }; + friend class TextHolderComponent; + friend class TextEditorViewport; + void drawContent (Graphics& g); + void updateTextHolderSize() throw(); + float getWordWrapWidth() const throw(); + void timerCallbackInt(); + void repaintCaret(); + void repaintText (int textStartIndex, int textEndIndex); - CriticalSection lock; - PendingMessage* firstMessage; + TextEditor (const TextEditor&); + const TextEditor& operator= (const TextEditor&); +}; - MidiOutput() throw(); - MidiOutput (const MidiOutput&); +#endif // __JUCE_TEXTEDITOR_JUCEHEADER__ +/********* End of inlined file: juce_TextEditor.h *********/ - void run(); -}; +class Label; -#endif // __JUCE_MIDIOUTPUT_JUCEHEADER__ -/********* End of inlined file: juce_MidiOutput.h *********/ +/** + A class for receiving events from a Label. -/********* Start of inlined file: juce_ComboBox.h *********/ -#ifndef __JUCE_COMBOBOX_JUCEHEADER__ -#define __JUCE_COMBOBOX_JUCEHEADER__ + You can register a LabelListener with a Label using the Label::addListener() + method, and it will be called when the text of the label changes, either because + of a call to Label::setText() or by the user editing the text (if the label is + editable). -/********* Start of inlined file: juce_Label.h *********/ -#ifndef __JUCE_LABEL_JUCEHEADER__ -#define __JUCE_LABEL_JUCEHEADER__ + @see Label::addListener, Label::removeListener +*/ +class JUCE_API LabelListener +{ +public: + /** Destructor. */ + virtual ~LabelListener() {} -/********* Start of inlined file: juce_ComponentDeletionWatcher.h *********/ -#ifndef __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ -#define __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ + /** Called when a Label's text has changed. + */ + virtual void labelTextChanged (Label* labelThatHasChanged) = 0; +}; /** - Object for monitoring a component, and later testing whether it's still valid. - - Slightly obscure, this one, but it's used internally for making sure that - after some callbacks, a component hasn't been deleted. It's more reliable than - just using isValidComponent(), which can provide false-positives if a new - component is created at the same memory location as an old one. + A component that displays a text string, and can optionally become a text + editor when clicked. */ -class JUCE_API ComponentDeletionWatcher +class JUCE_API Label : public Component, + public SettableTooltipClient, + protected TextEditorListener, + private ComponentListener { public: - /** Creates a watcher for a given component. + /** Creates a Label. - The component must be valid at the time it's passed in. + @param componentName the name to give the component + @param labelText the text to show in the label */ - ComponentDeletionWatcher (const Component* const componentToWatch) throw(); + Label (const String& componentName, + const String& labelText); /** Destructor. */ - ~ComponentDeletionWatcher() throw(); - - /** Returns true if the component has been deleted since the time that this - object was created. - */ - bool hasBeenDeleted() const throw(); - - /** Returns the component that's being watched, or null if it has been deleted. */ - const Component* getComponent() const throw(); - - juce_UseDebuggingNewOperator + ~Label(); -private: - const Component* const componentToWatch; - const uint32 componentUID; + /** Changes the label text. - ComponentDeletionWatcher (const ComponentDeletionWatcher&); - const ComponentDeletionWatcher& operator= (const ComponentDeletionWatcher&); -}; + If broadcastChangeMessage is true and the new text is different to the current + text, then the class will broadcast a change message to any LabelListeners that + are registered. + */ + void setText (const String& newText, + const bool broadcastChangeMessage); -#endif // __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ -/********* End of inlined file: juce_ComponentDeletionWatcher.h *********/ + /** Returns the label's current text. -/********* Start of inlined file: juce_TextEditor.h *********/ -#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ -#define __JUCE_TEXTEDITOR_JUCEHEADER__ + @param returnActiveEditorContents if this is true and the label is currently + being edited, then this method will return the + text as it's being shown in the editor. If false, + then the value returned here won't be updated until + the user has finished typing and pressed the return + key. + */ + const String getText (const bool returnActiveEditorContents = false) const throw(); -class TextEditor; -class TextHolderComponent; + /** Changes the font to use to draw the text. -/** - Receives callbacks from a TextEditor component when it changes. + @see getFont + */ + void setFont (const Font& newFont) throw(); - @see TextEditor::addListener -*/ -class JUCE_API TextEditorListener -{ -public: - /** Destructor. */ - virtual ~TextEditorListener() {} + /** Returns the font currently being used. - /** Called when the user changes the text in some way. */ - virtual void textEditorTextChanged (TextEditor& editor) = 0; + @see setFont + */ + const Font& getFont() const throw(); - /** Called when the user presses the return key. */ - virtual void textEditorReturnKeyPressed (TextEditor& editor) = 0; + /** A set of colour IDs to use to change the colour of various aspects of the label. - /** Called when the user presses the escape key. */ - virtual void textEditorEscapeKeyPressed (TextEditor& editor) = 0; + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - /** Called when the text editor loses focus. */ - virtual void textEditorFocusLost (TextEditor& editor) = 0; -}; + Note that you can also use the constants from TextEditor::ColourIds to change the + colour of the text editor that is opened when a label is editable. -/** - A component containing text that can be edited. + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */ + textColourId = 0x1000281, /**< The colour for the text. */ + outlineColourId = 0x1000282 /**< An optional colour to use to draw a border around the label. + Leave this transparent to not have an outline. */ + }; - A TextEditor can either be in single- or multi-line mode, and supports mixed - fonts and colours. + /** Sets the style of justification to be used for positioning the text. - @see TextEditorListener, Label -*/ -class JUCE_API TextEditor : public Component, - public SettableTooltipClient -{ -public: + (The default is Justification::centredLeft) + */ + void setJustificationType (const Justification& justification) throw(); - /** Creates a new, empty text editor. + /** Returns the type of justification, as set in setJustificationType(). */ + const Justification getJustificationType() const throw() { return justification; } - @param componentName the name to pass to the component for it to use as its name - @param passwordCharacter if this is not zero, this character will be used as a replacement - for all characters that are drawn on screen - e.g. to create - a password-style textbox containing circular blobs instead of text, - you could set this value to 0x25cf, which is the unicode character - for a black splodge (not all fonts include this, though), or 0x2022, - which is a bullet (probably the best choice for linux). + /** Changes the gap that is left between the edge of the component and the text. + By default there's a small gap left at the sides of the component to allow for + the drawing of the border, but you can change this if necessary. */ - TextEditor (const String& componentName = String::empty, - const tchar passwordCharacter = 0); + void setBorderSize (int horizontalBorder, int verticalBorder); - /** Destructor. */ - virtual ~TextEditor(); + /** Returns the size of the horizontal gap being left around the text. + */ + int getHorizontalBorderSize() const throw() { return horizontalBorderSize; } - /** Puts the editor into either multi- or single-line mode. + /** Returns the size of the vertical gap being left around the text. + */ + int getVerticalBorderSize() const throw() { return verticalBorderSize; } - By default, the editor will be in single-line mode, so use this if you need a multi-line - editor. + /** Makes this label "stick to" another component. - See also the setReturnKeyStartsNewLine() method, which will also need to be turned - on if you want a multi-line editor with line-breaks. + This will cause the label to follow another component around, staying + either to its left or above it. - @see isMultiLine, setReturnKeyStartsNewLine + @param owner the component to follow + @param onLeft if true, the label will stay on the left of its component; if + false, it will stay above it. */ - void setMultiLine (const bool shouldBeMultiLine, - const bool shouldWordWrap = true); + void attachToComponent (Component* owner, + const bool onLeft); - /** Returns true if the editor is in multi-line mode. + /** If this label has been attached to another component using attachToComponent, this + returns the other component. + + Returns 0 if the label is not attached. */ - bool isMultiLine() const throw(); + Component* getAttachedComponent() const throw() { return ownerComponent; } - /** Changes the behaviour of the return key. + /** If the label is attached to the left of another component, this returns true. - If set to true, the return key will insert a new-line into the text; if false - it will trigger a call to the TextEditorListener::textEditorReturnKeyPressed() - method. By default this is set to false, and when true it will only insert - new-lines when in multi-line mode (see setMultiLine()). + Returns false if the label is above the other component. This is only relevent if + attachToComponent() has been called. */ - void setReturnKeyStartsNewLine (const bool shouldStartNewLine); + bool isAttachedOnLeft() const throw() { return leftOfOwnerComp; } - /** Returns the value set by setReturnKeyStartsNewLine(). + /** Specifies the minimum amount that the font can be squashed horizantally before it starts + using ellipsis. - See setReturnKeyStartsNewLine() for more info. + @see Graphics::drawFittedText */ - bool getReturnKeyStartsNewLine() const throw() { return returnKeyStartsNewLine; } + void setMinimumHorizontalScale (const float newScale); - /** Indicates whether the tab key should be accepted and used to input a tab character, - or whether it gets ignored. + float getMinimumHorizontalScale() const throw() { return minimumHorizontalScale; } - By default the tab key is ignored, so that it can be used to switch keyboard focus - between components. - */ - void setTabKeyUsedAsCharacter (const bool shouldTabKeyBeUsed) throw(); + /** Registers a listener that will be called when the label's text changes. */ + void addListener (LabelListener* const listener) throw(); - /** Returns true if the tab key is being used for input. - @see setTabKeyUsedAsCharacter - */ - bool isTabKeyUsedAsCharacter() const throw() { return tabKeyUsed; } + /** Deregisters a previously-registered listener. */ + void removeListener (LabelListener* const listener) throw(); - /** Changes the editor to read-only mode. + /** Makes the label turn into a TextEditor when clicked. - By default, the text editor is not read-only. If you're making it read-only, you - might also want to call setCaretVisible (false) to get rid of the caret. + By default this is turned off. - The text can still be highlighted and copied when in read-only mode. + If turned on, then single- or double-clicking will turn the label into + an editor. If the user then changes the text, then the ChangeBroadcaster + base class will be used to send change messages to any listeners that + have registered. - @see isReadOnly, setCaretVisible - */ - void setReadOnly (const bool shouldBeReadOnly); + If the user changes the text, the textWasEdited() method will be called + afterwards, and subclasses can override this if they need to do anything + special. - /** Returns true if the editor is in read-only mode. + @param editOnSingleClick if true, just clicking once on the label will start editing the text + @param editOnDoubleClick if true, a double-click is needed to start editing + @param lossOfFocusDiscardsChanges if true, clicking somewhere else while the text is being + edited will discard any changes; if false, then this will + commit the changes. + @see showEditor, setEditorColours, TextEditor */ - bool isReadOnly() const throw(); - - /** Makes the caret visible or invisible. + void setEditable (const bool editOnSingleClick, + const bool editOnDoubleClick = false, + const bool lossOfFocusDiscardsChanges = false) throw(); - By default the caret is visible. + /** Returns true if this option was set using setEditable(). */ + bool isEditableOnSingleClick() const throw() { return editSingleClick; } - @see setCaretColour, setCaretPosition - */ - void setCaretVisible (const bool shouldBeVisible) throw(); + /** Returns true if this option was set using setEditable(). */ + bool isEditableOnDoubleClick() const throw() { return editDoubleClick; } - /** Returns true if the caret is enabled. - @see setCaretVisible - */ - bool isCaretVisible() const throw() { return caretVisible; } + /** Returns true if this option has been set in a call to setEditable(). */ + bool doesLossOfFocusDiscardChanges() const throw() { return lossOfFocusDiscardsChanges; } - /** Enables/disables a vertical scrollbar. + /** Returns true if the user can edit this label's text. */ + bool isEditable() const throw() { return editSingleClick || editDoubleClick; } - (This only applies when in multi-line mode). When the text gets too long to fit - in the component, a scrollbar can appear to allow it to be scrolled. Even when - this is enabled, the scrollbar will be hidden unless it's needed. + /** Makes the editor appear as if the label had been clicked by the user. - By default the scrollbar is enabled. + @see textWasEdited, setEditable */ - void setScrollbarsShown (bool shouldBeEnabled) throw(); + void showEditor(); - /** Returns true if scrollbars are enabled. - @see setScrollbarsShown + /** Hides the editor if it was being shown. + + @param discardCurrentEditorContents if true, the label's text will be + reset to whatever it was before the editor + was shown; if false, the current contents of the + editor will be used to set the label's text + before it is hidden. */ - bool areScrollbarsShown() const throw() { return scrollbarVisible; } + void hideEditor (const bool discardCurrentEditorContents); - /** Changes the password character used to disguise the text. + /** Returns true if the editor is currently focused and active. */ + bool isBeingEdited() const throw(); - @param passwordCharacter if this is not zero, this character will be used as a replacement - for all characters that are drawn on screen - e.g. to create - a password-style textbox containing circular blobs instead of text, - you could set this value to 0x25cf, which is the unicode character - for a black splodge (not all fonts include this, though), or 0x2022, - which is a bullet (probably the best choice for linux). - */ - void setPasswordCharacter (const tchar passwordCharacter) throw(); + juce_UseDebuggingNewOperator - /** Returns the current password character. - @see setPasswordCharacter -l */ - tchar getPasswordCharacter() const throw() { return passwordCharacter; } +protected: + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void mouseDoubleClick (const MouseEvent& e); + /** @internal */ + void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); + /** @internal */ + void componentParentHierarchyChanged (Component& component); + /** @internal */ + void componentVisibilityChanged (Component& component); + /** @internal */ + void inputAttemptWhenModal(); + /** @internal */ + void focusGained (FocusChangeType); + /** @internal */ + void enablementChanged(); + /** @internal */ + KeyboardFocusTraverser* createFocusTraverser(); + /** @internal */ + void textEditorTextChanged (TextEditor& editor); + /** @internal */ + void textEditorReturnKeyPressed (TextEditor& editor); + /** @internal */ + void textEditorEscapeKeyPressed (TextEditor& editor); + /** @internal */ + void textEditorFocusLost (TextEditor& editor); + /** @internal */ + void colourChanged(); - /** Allows a right-click menu to appear for the editor. + /** Creates the TextEditor component that will be used when the user has clicked on the label. - (This defaults to being enabled). + Subclasses can override this if they need to customise this component in some way. + */ + virtual TextEditor* createEditorComponent(); - If enabled, right-clicking (or command-clicking on the Mac) will pop up a menu - of options such as cut/copy/paste, undo/redo, etc. + /** Called after the user changes the text. */ - void setPopupMenuEnabled (const bool menuEnabled) throw(); + virtual void textWasEdited(); - /** Returns true if the right-click menu is enabled. - @see setPopupMenuEnabled + /** Called when the text has been altered. */ - bool isPopupMenuEnabled() const throw() { return popupMenuEnabled; } + virtual void textWasChanged(); - /** Returns true if a popup-menu is currently being displayed. + /** Called when the text editor has just appeared, due to a user click or other + focus change. */ - bool isPopupMenuCurrentlyActive() const throw() { return menuActive; } + virtual void editorShown (TextEditor* editorComponent); - /** A set of colour IDs to use to change the colour of various aspects of the editor. + /** Called when the text editor is going to be deleted, after editing has finished. + */ + virtual void editorAboutToBeHidden (TextEditor* editorComponent); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. +private: + String text; + Font font; + Justification justification; + TextEditor* editor; + SortedSet listeners; + Component* ownerComponent; + ComponentDeletionWatcher* deletionWatcher; + int horizontalBorderSize, verticalBorderSize; + float minimumHorizontalScale; + bool editSingleClick : 1; + bool editDoubleClick : 1; + bool lossOfFocusDiscardsChanges : 1; + bool leftOfOwnerComp : 1; - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - backgroundColourId = 0x1000200, /**< The colour to use for the text component's background - this can be - transparent if necessary. */ + bool updateFromTextEditorContents(); + void callChangeListeners(); - textColourId = 0x1000201, /**< The colour that will be used when text is added to the editor. Note - that because the editor can contain multiple colours, calling this - method won't change the colour of existing text - to do that, call - applyFontToAllText() after calling this method.*/ + Label (const Label&); + const Label& operator= (const Label&); +}; - highlightColourId = 0x1000202, /**< The colour with which to fill the background of highlighted sections of - the text - this can be transparent if you don't want to show any - highlighting.*/ +#endif // __JUCE_LABEL_JUCEHEADER__ +/********* End of inlined file: juce_Label.h *********/ - highlightedTextColourId = 0x1000203, /**< The colour with which to draw the text in highlighted sections. */ +class ComboBox; - caretColourId = 0x1000204, /**< The colour with which to draw the caret. */ +/** + A class for receiving events from a ComboBox. - outlineColourId = 0x1000205, /**< If this is non-transparent, it will be used to draw a box around - the edge of the component. */ + You can register a ComboBoxListener with a ComboBox using the ComboBox::addListener() + method, and it will be called when the selected item in the box changes. - focusedOutlineColourId = 0x1000206, /**< If this is non-transparent, it will be used to draw a box around - the edge of the component when it has focus. */ + @see ComboBox::addListener, ComboBox::removeListener +*/ +class JUCE_API ComboBoxListener +{ +public: + /** Destructor. */ + virtual ~ComboBoxListener() {} - shadowColourId = 0x1000207, /**< If this is non-transparent, it'll be used to draw an inner shadow - around the edge of the editor. */ - }; + /** Called when a ComboBox has its selected item changed. + */ + virtual void comboBoxChanged (ComboBox* comboBoxThatHasChanged) = 0; +}; - /** Sets the font to use for newly added text. +/** + A component that lets the user choose from a drop-down list of choices. - This will change the font that will be used next time any text is added or entered - into the editor. It won't change the font of any existing text - to do that, use - applyFontToAllText() instead. + The combo-box has a list of text strings, each with an associated id number, + that will be shown in the drop-down list when the user clicks on the component. - @see applyFontToAllText - */ - void setFont (const Font& newFont) throw(); + The currently selected choice is displayed in the combo-box, and this can + either be read-only text, or editable. - /** Applies a font to all the text in the editor. + To find out when the user selects a different item or edits the text, you + can register a ComboBoxListener to receive callbacks. - This will also set the current font to use for any new text that's added. + @see ComboBoxListener +*/ +class JUCE_API ComboBox : public Component, + public SettableTooltipClient, + private LabelListener, + private AsyncUpdater +{ +public: - @see setFont - */ - void applyFontToAllText (const Font& newFont); + /** Creates a combo-box. - /** Returns the font that's currently being used for new text. + On construction, the text field will be empty, so you should call the + setSelectedId() or setText() method to choose the initial value before + displaying it. - @see setFont + @param componentName the name to set for the component (see Component::setName()) */ - const Font getFont() const throw(); + ComboBox (const String& componentName); - /** If set to true, focusing on the editor will highlight all its text. + /** Destructor. */ + ~ComboBox(); - (Set to false by default). + /** Sets whether the test in the combo-box is editable. - This is useful for boxes where you expect the user to re-enter all the - text when they focus on the component, rather than editing what's already there. + The default state for a new ComboBox is non-editable, and can only be changed + by choosing from the drop-down list. */ - void setSelectAllWhenFocused (const bool b) throw(); - - /** Sets limits on the characters that can be entered. + void setEditableText (const bool isEditable); - @param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no - limit is set - @param allowedCharacters if this is non-empty, then only characters that occur in - this string are allowed to be entered into the editor. + /** Returns true if the text is directly editable. + @see setEditableText */ - void setInputRestrictions (const int maxTextLength, - const String& allowedCharacters = String::empty) throw(); + bool isTextEditable() const throw(); - /** When the text editor is empty, it can be set to display a message. + /** Sets the style of justification to be used for positioning the text. - This is handy for things like telling the user what to type in the box - the - string is only displayed, it's not taken to actually be the contents of - the editor. + The default is Justification::centredLeft. The text is displayed using a + Label component inside the ComboBox. */ - void setTextToShowWhenEmpty (const String& text, const Colour& colourToUse) throw(); - - /** Changes the size of the scrollbars that are used. + void setJustificationType (const Justification& justification) throw(); - Handy if you need smaller scrollbars for a small text box. + /** Returns the current justification for the text box. + @see setJustificationType */ - void setScrollBarThickness (const int newThicknessPixels); + const Justification getJustificationType() const throw(); - /** Shows or hides the buttons on any scrollbars that are used. + /** Adds an item to be shown in the drop-down list. - @see ScrollBar::setButtonVisibility + @param newItemText the text of the item to show in the list + @param newItemId an associated ID number that can be set or retrieved - see + getSelectedId() and setSelectedId() + @see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId */ - void setScrollBarButtonVisibility (const bool buttonsVisible); + void addItem (const String& newItemText, + const int newItemId) throw(); - /** Registers a listener to be told when things happen to the text. + /** Adds a separator line to the drop-down list. - @see removeListener + This is like adding a separator to a popup menu. See PopupMenu::addSeparator(). */ - void addListener (TextEditorListener* const newListener) throw(); + void addSeparator() throw(); - /** Deregisters a listener. + /** Adds a heading to the drop-down list, so that you can group the items into + different sections. - @see addListener + The headings are indented slightly differently to set them apart from the + items on the list, and obviously can't be selected. You might want to add + separators between your sections too. + + @see addItem, addSeparator */ - void removeListener (TextEditorListener* const listenerToRemove) throw(); + void addSectionHeading (const String& headingName) throw(); - /** Returns the entire contents of the editor. */ - const String getText() const throw(); + /** This allows items in the drop-down list to be selectively disabled. - /** Returns a section of the contents of the editor. */ - const String getTextSubstring (const int startCharacter, const int endCharacter) const throw(); + When you add an item, it's enabled by default, but you can call this + method to change its status. - /** Returns true if there are no characters in the editor. + If you disable an item which is already selected, this won't change the + current selection - it just stops the user choosing that item from the list. + */ + void setItemEnabled (const int itemId, + const bool shouldBeEnabled) throw(); - This is more efficient than calling getText().isEmpty(). + /** Changes the text for an existing item. */ - bool isEmpty() const throw(); + void changeItemText (const int itemId, + const String& newText) throw(); - /** Sets the entire content of the editor. + /** Removes all the items from the drop-down list. - This will clear the editor and insert the given text (using the current text colour - and font). You can set the current text colour using - @code setColour (TextEditor::textColourId, ...); - @endcode + If this call causes the content to be cleared, then a change-message + will be broadcast unless dontSendChangeMessage is true. - @param newText the text to add - @param sendTextChangeMessage if true, this will cause a change message to - be sent to all the listeners. - @see insertText + @see addItem, removeItem, getNumItems */ - void setText (const String& newText, - const bool sendTextChangeMessage = true); + void clear (const bool dontSendChangeMessage = false); - /** Inserts some text at the current cursor position. + /** Returns the number of items that have been added to the list. - If a section of the text is highlighted, it will be replaced by - this string, otherwise it will be inserted. - - To delete a section of text, you can use setHighlightedRegion() to - highlight it, and call insertTextAtCursor (String::empty). - - @see setCaretPosition, getCaretPosition, setHighlightedRegion + Note that this doesn't include headers or separators. */ - void insertTextAtCursor (String textToInsert); + int getNumItems() const throw(); - /** Deletes all the text from the editor. */ - void clear(); + /** Returns the text for one of the items in the list. - /** Deletes the currently selected region, and puts it on the clipboard. + Note that this doesn't include headers or separators. - @see copy, paste, SystemClipboard + @param index the item's index from 0 to (getNumItems() - 1) */ - void cut(); - - /** Copies any currently selected region to the clipboard. + const String getItemText (const int index) const throw(); - @see cut, paste, SystemClipboard - */ - void copy(); + /** Returns the ID for one of the items in the list. - /** Pastes the contents of the clipboard into the editor at the cursor position. + Note that this doesn't include headers or separators. - @see cut, copy, SystemClipboard + @param index the item's index from 0 to (getNumItems() - 1) */ - void paste(); - - /** Moves the caret to be in front of a given character. + int getItemId (const int index) const throw(); - @see getCaretPosition - */ - void setCaretPosition (const int newIndex) throw(); + /** Returns the ID of the item that's currently shown in the box. - /** Returns the current index of the caret. + If no item is selected, or if the text is editable and the user + has entered something which isn't one of the items in the list, then + this will return 0. - @see setCaretPosition + @see setSelectedId, getSelectedItemIndex, getText */ - int getCaretPosition() const throw(); + int getSelectedId() const throw(); - /** Attempts to scroll the text editor so that the caret ends up at - a specified position. + /** Sets one of the items to be the current selection. - This won't affect the caret's position within the text, it tries to scroll - the entire editor vertically and horizontally so that the caret is sitting - at the given position (relative to the top-left of this component). + This will set the ComboBox's text to that of the item that matches + this ID. - Depending on the amount of text available, it might not be possible to - scroll far enough for the caret to reach this exact position, but it - will go as far as it can in that direction. + @param newItemId the new item to select + @param dontSendChangeMessage if set to true, this method won't trigger a + change notification + @see getSelectedId, setSelectedItemIndex, setText */ - void scrollEditorToPositionCaret (const int desiredCaretX, - const int desiredCaretY) throw(); + void setSelectedId (const int newItemId, + const bool dontSendChangeMessage = false) throw(); - /** Get the graphical position of the caret. + /** Returns the index of the item that's currently shown in the box. - The rectangle returned is relative to the component's top-left corner. - @see scrollEditorToPositionCaret - */ - const Rectangle getCaretRectangle() throw(); + If no item is selected, or if the text is editable and the user + has entered something which isn't one of the items in the list, then + this will return -1. - /** Selects a section of the text. + @see setSelectedItemIndex, getSelectedId, getText */ - void setHighlightedRegion (int startIndex, - int numberOfCharactersToHighlight) throw(); + int getSelectedItemIndex() const throw(); - /** Returns the first character that is selected. + /** Sets one of the items to be the current selection. - If nothing is selected, this will still return a character index, but getHighlightedRegionLength() - will return 0. + This will set the ComboBox's text to that of the item at the given + index in the list. - @see setHighlightedRegion, getHighlightedRegionLength + @param newItemIndex the new item to select + @param dontSendChangeMessage if set to true, this method won't trigger a + change notification + @see getSelectedItemIndex, setSelectedId, setText */ - int getHighlightedRegionStart() const throw() { return selectionStart; } + void setSelectedItemIndex (const int newItemIndex, + const bool dontSendChangeMessage = false) throw(); - /** Returns the number of characters that are selected. + /** Returns the text that is currently shown in the combo-box's text field. - @see setHighlightedRegion, getHighlightedRegionStart + If the ComboBox has editable text, then this text may have been edited + by the user; otherwise it will be one of the items from the list, or + possibly an empty string if nothing was selected. + + @see setText, getSelectedId, getSelectedItemIndex */ - int getHighlightedRegionLength() const throw() { return jmax (0, selectionEnd - selectionStart); } + const String getText() const throw(); - /** Returns the section of text that is currently selected. */ - const String getHighlightedText() const throw(); + /** Sets the contents of the combo-box's text field. - /** Finds the index of the character at a given position. + The text passed-in will be set as the current text regardless of whether + it is one of the items in the list. If the current text isn't one of the + items, then getSelectedId() will return -1, otherwise it wil return + the approriate ID. - The co-ordinates are relative to the component's top-left. + @param newText the text to select + @param dontSendChangeMessage if set to true, this method won't trigger a + change notification + @see getText */ - int getTextIndexAt (const int x, const int y) throw(); + void setText (const String& newText, + const bool dontSendChangeMessage = false) throw(); - /** Counts the number of characters in the text. + /** Programmatically opens the text editor to allow the user to edit the current item. - This is quicker than getting the text as a string if you just need to know - the length. + This is the same effect as when the box is clicked-on. + @see Label::showEditor(); */ - int getTotalNumChars() throw(); + void showEditor(); - /** Returns the total width of the text, as it is currently laid-out. + /** Registers a listener that will be called when the box's content changes. */ + void addListener (ComboBoxListener* const listener) throw(); - This may be larger than the size of the TextEditor, and can change when - the TextEditor is resized or the text changes. - */ - int getTextWidth() const throw(); + /** Deregisters a previously-registered listener. */ + void removeListener (ComboBoxListener* const listener) throw(); - /** Returns the maximum height of the text, as it is currently laid-out. + /** Sets a message to display when there is no item currently selected. - This may be larger than the size of the TextEditor, and can change when - the TextEditor is resized or the text changes. + @see getTextWhenNothingSelected */ - int getTextHeight() const throw(); + void setTextWhenNothingSelected (const String& newMessage) throw(); - /** Changes the size of the gap at the top and left-edge of the editor. + /** Returns the text that is shown when no item is selected. - By default there's a gap of 4 pixels. + @see setTextWhenNothingSelected */ - void setIndents (const int newLeftIndent, const int newTopIndent) throw(); + const String getTextWhenNothingSelected() const throw(); - /** Changes the size of border left around the edge of the component. + /** Sets the message to show when there are no items in the list, and the user clicks + on the drop-down box. - @see getBorder + By default it just says "no choices", but this lets you change it to something more + meaningful. */ - void setBorder (const BorderSize& border) throw(); - - /** Returns the size of border around the edge of the component. + void setTextWhenNoChoicesAvailable (const String& newMessage) throw(); - @see setBorder + /** Returns the text shown when no items have been added to the list. + @see setTextWhenNoChoicesAvailable */ - const BorderSize getBorder() const throw(); + const String getTextWhenNoChoicesAvailable() const throw(); - /** Used to disable the auto-scrolling which keeps the cursor visible. + /** Gives the ComboBox a tooltip. */ + void setTooltip (const String& newTooltip); - If true (the default), the editor will scroll when the cursor moves offscreen. If - set to false, it won't. + /** A set of colour IDs to use to change the colour of various aspects of the combo box. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + To change the colours of the menu that pops up + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void setScrollToShowCursor (const bool shouldScrollToShowCursor) throw(); + enum ColourIds + { + backgroundColourId = 0x1000b00, /**< The background colour to fill the box with. */ + textColourId = 0x1000a00, /**< The colour for the text in the box. */ + outlineColourId = 0x1000c00, /**< The colour for an outline around the box. */ + buttonColourId = 0x1000d00, /**< The base colour for the button (a LookAndFeel class will probably use variations on this). */ + arrowColourId = 0x1000e00, /**< The colour for the arrow shape that pops up the menu */ + }; /** @internal */ - void paint (Graphics& g); + void labelTextChanged (Label*); /** @internal */ - void paintOverChildren (Graphics& g); + void enablementChanged(); /** @internal */ - void mouseDown (const MouseEvent& e); + void colourChanged(); /** @internal */ - void mouseUp (const MouseEvent& e); + void focusGained (Component::FocusChangeType cause); /** @internal */ - void mouseDrag (const MouseEvent& e); + void focusLost (Component::FocusChangeType cause); /** @internal */ - void mouseDoubleClick (const MouseEvent& e); + void handleAsyncUpdate(); /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + const String getTooltip() { return label->getTooltip(); } /** @internal */ - bool keyPressed (const KeyPress& key); + void mouseDown (const MouseEvent&); /** @internal */ - bool keyStateChanged (const bool isKeyDown); + void mouseDrag (const MouseEvent&); /** @internal */ - void focusGained (FocusChangeType cause); + void mouseUp (const MouseEvent&); /** @internal */ - void focusLost (FocusChangeType cause); + void lookAndFeelChanged(); + /** @internal */ + void paint (Graphics&); /** @internal */ void resized(); /** @internal */ - void enablementChanged(); + bool keyStateChanged (const bool isKeyDown); /** @internal */ - void colourChanged(); + bool keyPressed (const KeyPress&); juce_UseDebuggingNewOperator -protected: +private: + struct ItemInfo + { + String name; + int itemId; + bool isEnabled : 1, isHeading : 1; - /** This adds the items to the popup menu. + bool isSeparator() const throw(); + bool isRealItem() const throw(); + }; - By default it adds the cut/copy/paste items, but you can override this if - you need to replace these with your own items. + OwnedArray items; + int currentIndex; + bool isButtonDown; + bool separatorPending; + bool menuActive; + SortedSet listeners; + Label* label; + String textWhenNothingSelected, noChoicesMessage; - If you want to add your own items to the existing ones, you can override this, - call the base class's addPopupMenuItems() method, then append your own items. + void showPopup(); - When the menu has been shown, performPopupMenuAction() will be called to - perform the item that the user has chosen. + ItemInfo* getItemForId (const int itemId) const throw(); + ItemInfo* getItemForIndex (const int index) const throw(); - The default menu items will be added using item IDs in the range - 0x7fff0000 - 0x7fff1000, so you should avoid those values for your own - menu IDs. + ComboBox (const ComboBox&); + const ComboBox& operator= (const ComboBox&); +}; - If this was triggered by a mouse-click, the mouseClickEvent parameter will be - a pointer to the info about it, or may be null if the menu is being triggered - by some other means. +#endif // __JUCE_COMBOBOX_JUCEHEADER__ +/********* End of inlined file: juce_ComboBox.h *********/ - @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled - */ - virtual void addPopupMenuItems (PopupMenu& menuToAddTo, - const MouseEvent* mouseClickEvent); +/** + Manages the state of some audio and midi i/o devices. - /** This is called to perform one of the items that was shown on the popup menu. + This class keeps tracks of a currently-selected audio device, through + with which it continuously streams data from an audio callback, as well as + one or more midi inputs. - If you've overridden addPopupMenuItems(), you should also override this - to perform the actions that you've added. + The idea is that your application will create one global instance of this object, + and let it take care of creating and deleting specific types of audio devices + internally. So when the device is changed, your callbacks will just keep running + without having to worry about this. - If you've overridden addPopupMenuItems() but have still left the default items - on the menu, remember to call the superclass's performPopupMenuAction() - so that it can perform the default actions if that's what the user clicked on. + The manager can save and reload all of its device settings as XML, which + makes it very easy for you to save and reload the audio setup of your + application. - @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled - */ - virtual void performPopupMenuAction (const int menuItemID); + And to make it easy to let the user change its settings, there's a component + to do just that - the AudioDeviceSelectorComponent class, which contains a set of + device selection/sample-rate/latency controls. - /** Scrolls the minimum distance needed to get the caret into view. */ - void scrollToMakeSureCursorIsVisible() throw(); + To use an AudioDeviceManager, create one, and use initialise() to set it up. Then + call addAudioCallback() to register your audio callback with it, and use that to process + your audio data. - /** @internal */ - void moveCaret (int newCaretPos) throw(); + The manager also acts as a handy hub for incoming midi messages, allowing a + listener to register for messages from either a specific midi device, or from whatever + the current default midi input device is. The listener then doesn't have to worry about + re-registering with different midi devices if they are changed or deleted. - /** @internal */ - void moveCursorTo (const int newPosition, const bool isSelecting) throw(); + And yet another neat trick is that amount of CPU time being used is measured and + available with the getCpuUsage() method. - /** Used internally to dispatch a text-change message. */ - void textChanged() throw(); + The AudioDeviceManager is a ChangeBroadcaster, and will send a change message to + listeners whenever one of its settings is changed. - /** Begins a new transaction in the UndoManager. - */ - void newTransaction() throw(); + @see AudioDeviceSelectorComponent, AudioIODevice, AudioIODeviceType +*/ +class JUCE_API AudioDeviceManager : public ChangeBroadcaster +{ +public: - /** Used internally to trigger an undo or redo. */ - void doUndoRedo (const bool isRedo); + /** Creates a default AudioDeviceManager. - /** Can be overridden to intercept return key presses directly */ - virtual void returnPressed(); + Initially no audio device will be selected. You should call the initialise() method + and register an audio callback with setAudioCallback() before it'll be able to + actually make any noise. + */ + AudioDeviceManager(); - /** Can be overridden to intercept escape key presses directly */ - virtual void escapePressed(); + /** Destructor. */ + ~AudioDeviceManager(); - /** @internal */ - void handleCommandMessage (int commandId); + /** + This structure holds a set of properties describing the current audio setup. -private: + @see AudioDeviceManager::setAudioDeviceSetup() + */ + struct JUCE_API AudioDeviceSetup + { + AudioDeviceSetup(); + bool operator== (const AudioDeviceSetup& other) const; - Viewport* viewport; - TextHolderComponent* textHolder; - BorderSize borderSize; + /** The name of the audio device used for output. + The name has to be one of the ones listed by the AudioDeviceManager's currently + selected device type. + This may be the same as the input device. + */ + String outputDeviceName; - bool readOnly : 1; - bool multiline : 1; - bool wordWrap : 1; - bool returnKeyStartsNewLine : 1; - bool caretVisible : 1; - bool popupMenuEnabled : 1; - bool selectAllTextWhenFocused : 1; - bool scrollbarVisible : 1; - bool wasFocused : 1; - bool caretFlashState : 1; - bool keepCursorOnScreen : 1; - bool tabKeyUsed : 1; - bool menuActive : 1; + /** The name of the audio device used for input. + This may be the same as the output device. + */ + String inputDeviceName; - UndoManager undoManager; - float cursorX, cursorY, cursorHeight; - int maxTextLength; - int selectionStart, selectionEnd; - int leftIndent, topIndent; - unsigned int lastTransactionTime; - Font currentFont; - int totalNumChars, caretPosition; - VoidArray sections; - String textToShowWhenEmpty; - Colour colourForTextWhenEmpty; - tchar passwordCharacter; + /** The current sample rate. + This rate is used for both the input and output devices. + */ + double sampleRate; - enum - { - notDragging, - draggingSelectionStart, - draggingSelectionEnd - } dragType; + /** The buffer size, in samples. + This buffer size is used for both the input and output devices. + */ + int bufferSize; - String allowedCharacters; - SortedSet listeners; + /** The set of active input channels. + The bits that are set in this array indicate the channels of the + input device that are active. + */ + BitArray inputChannels; - friend class TextEditorInsertAction; - friend class TextEditorRemoveAction; + /** If this is true, it indicates that the inputChannels array + should be ignored, and instead, the device's default channels + should be used. + */ + bool useDefaultInputChannels; - void coalesceSimilarSections() throw(); - void splitSection (const int sectionIndex, const int charToSplitAt) throw(); + /** The set of active output channels. + The bits that are set in this array indicate the channels of the + input device that are active. + */ + BitArray outputChannels; - void clearInternal (UndoManager* const um) throw(); + /** If this is true, it indicates that the outputChannels array + should be ignored, and instead, the device's default channels + should be used. + */ + bool useDefaultOutputChannels; + }; - void insert (const String& text, - const int insertIndex, - const Font& font, - const Colour& colour, - UndoManager* const um, - const int caretPositionToMoveTo) throw(); + /** Opens a set of audio devices ready for use. - void reinsert (const int insertIndex, - const VoidArray& sections) throw(); + This will attempt to open either a default audio device, or one that was + previously saved as XML. - void remove (const int startIndex, - int endIndex, - UndoManager* const um, - const int caretPositionToMoveTo) throw(); + @param numInputChannelsNeeded a minimum number of input channels needed + by your app. + @param numOutputChannelsNeeded a minimum number of output channels to open + @param savedState either a previously-saved state that was produced + by createStateXml(), or 0 if you want the manager + to choose the best device to open. + @param selectDefaultDeviceOnFailure if true, then if the device specified in the XML + fails to open, then a default device will be used + instead. If false, then on failure, no device is + opened. + @param preferredDefaultDeviceName if this is not empty, and there's a device with this + name, then that will be used as the default device + (assuming that there wasn't one specified in the XML). + The string can actually be a simple wildcard, containing "*" + and "?" characters + @param preferredSetupOptions if this is non-null, the structure will be used as the + set of preferred settings when opening the device. If you + use this parameter, the preferredDefaultDeviceName + field will be ignored - void getCharPosition (const int index, - float& x, float& y, - float& lineHeight) const throw(); + @returns an error message if anything went wrong, or an empty string if it worked ok. + */ + const String initialise (const int numInputChannelsNeeded, + const int numOutputChannelsNeeded, + const XmlElement* const savedState, + const bool selectDefaultDeviceOnFailure, + const String& preferredDefaultDeviceName = String::empty, + const AudioDeviceSetup* preferredSetupOptions = 0); - void updateCaretPosition() throw(); + /** Returns some XML representing the current state of the manager. - int indexAtPosition (const float x, - const float y) throw(); + This stores the current device, its samplerate, block size, etc, and + can be restored later with initialise(). + */ + XmlElement* createStateXml() const; - int findWordBreakAfter (const int position) const throw(); - int findWordBreakBefore (const int position) const throw(); + /** Returns the current device properties that are in use. - friend class TextHolderComponent; - friend class TextEditorViewport; - void drawContent (Graphics& g); - void updateTextHolderSize() throw(); - float getWordWrapWidth() const throw(); - void timerCallbackInt(); - void repaintCaret(); - void repaintText (int textStartIndex, int textEndIndex); + @see setAudioDeviceSetup + */ + void getAudioDeviceSetup (AudioDeviceSetup& setup); - TextEditor (const TextEditor&); - const TextEditor& operator= (const TextEditor&); -}; + /** Changes the current device or its settings. -#endif // __JUCE_TEXTEDITOR_JUCEHEADER__ -/********* End of inlined file: juce_TextEditor.h *********/ + If you want to change a device property, like the current sample rate or + block size, you can call getAudioDeviceSetup() to retrieve the current + settings, then tweak the appropriate fields in the AudioDeviceSetup structure, + and pass it back into this method to apply the new settings. -class Label; + @param newSetup the settings that you'd like to use + @param treatAsChosenDevice if this is true and if the device opens correctly, these new + settings will be taken as having been explicitly chosen by the + user, and the next time createStateXml() is called, these settings + will be returned. If it's false, then the device is treated as a + temporary or default device, and a call to createStateXml() will + return either the last settings that were made with treatAsChosenDevice + as true, or the last XML settings that were passed into initialise(). + @returns an error message if anything went wrong, or an empty string if it worked ok. -/** - A class for receiving events from a Label. + @see getAudioDeviceSetup + */ + const String setAudioDeviceSetup (const AudioDeviceSetup& newSetup, + const bool treatAsChosenDevice); - You can register a LabelListener with a Label using the Label::addListener() - method, and it will be called when the text of the label changes, either because - of a call to Label::setText() or by the user editing the text (if the label is - editable). + /** Returns the currently-active audio device. */ + AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; } - @see Label::addListener, Label::removeListener -*/ -class JUCE_API LabelListener -{ -public: - /** Destructor. */ - virtual ~LabelListener() {} - - /** Called when a Label's text has changed. + /** Returns the type of audio device currently in use. + @see setCurrentAudioDeviceType */ - virtual void labelTextChanged (Label* labelThatHasChanged) = 0; -}; - -/** - A component that displays a text string, and can optionally become a text - editor when clicked. -*/ -class JUCE_API Label : public Component, - public SettableTooltipClient, - protected TextEditorListener, - private ComponentListener -{ -public: - - /** Creates a Label. + const String getCurrentAudioDeviceType() const throw() { return currentDeviceType; } - @param componentName the name to give the component - @param labelText the text to show in the label + /** Returns the currently active audio device type object. + Don't keep a copy of this pointer - it's owned by the device manager and could + change at any time. */ - Label (const String& componentName, - const String& labelText); + AudioIODeviceType* getCurrentDeviceTypeObject() const; - /** Destructor. */ - ~Label(); + /** Changes the class of audio device being used. - /** Changes the label text. + This switches between, e.g. ASIO and DirectSound. On the Mac you probably won't ever call + this because there's only one type: CoreAudio. - If broadcastChangeMessage is true and the new text is different to the current - text, then the class will broadcast a change message to any LabelListeners that - are registered. + For a list of types, see getAvailableDeviceTypes(). */ - void setText (const String& newText, - const bool broadcastChangeMessage); + void setCurrentAudioDeviceType (const String& type, + const bool treatAsChosenDevice); - /** Returns the label's current text. + /** Closes the currently-open device. - @param returnActiveEditorContents if this is true and the label is currently - being edited, then this method will return the - text as it's being shown in the editor. If false, - then the value returned here won't be updated until - the user has finished typing and pressed the return - key. + You can call restartLastAudioDevice() later to reopen it in the same state + that it was just in. */ - const String getText (const bool returnActiveEditorContents = false) const throw(); - - /** Changes the font to use to draw the text. + void closeAudioDevice(); - @see getFont - */ - void setFont (const Font& newFont) throw(); + /** Tries to reload the last audio device that was running. - /** Returns the font currently being used. + Note that this only reloads the last device that was running before + closeAudioDevice() was called - it doesn't reload any kind of saved-state, + and can only be called after a device has been opened with SetAudioDevice(). - @see setFont + If a device is already open, this call will do nothing. */ - const Font& getFont() const throw(); + void restartLastAudioDevice(); - /** A set of colour IDs to use to change the colour of various aspects of the label. + /** Registers an audio callback to be used. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + The manager will redirect callbacks from whatever audio device is currently + in use to all registered callback objects. If more than one callback is + active, they will all be given the same input data, and their outputs will + be summed. - Note that you can also use the constants from TextEditor::ColourIds to change the - colour of the text editor that is opened when a label is editable. + If necessary, this method will invoke audioDeviceAboutToStart() on the callback + object before returning. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + To remove a callback, use removeAudioCallback(). */ - enum ColourIds - { - backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */ - textColourId = 0x1000281, /**< The colour for the text. */ - outlineColourId = 0x1000282 /**< An optional colour to use to draw a border around the label. - Leave this transparent to not have an outline. */ - }; - - /** Sets the style of justification to be used for positioning the text. + void addAudioCallback (AudioIODeviceCallback* newCallback); - (The default is Justification::centredLeft) - */ - void setJustificationType (const Justification& justification) throw(); + /** Deregisters a previously added callback. - /** Returns the type of justification, as set in setJustificationType(). */ - const Justification getJustificationType() const throw() { return justification; } + If necessary, this method will invoke audioDeviceStopped() on the callback + object before returning. - /** Changes the gap that is left between the edge of the component and the text. - By default there's a small gap left at the sides of the component to allow for - the drawing of the border, but you can change this if necessary. + @see addAudioCallback */ - void setBorderSize (int horizontalBorder, int verticalBorder); + void removeAudioCallback (AudioIODeviceCallback* callback); - /** Returns the size of the horizontal gap being left around the text. - */ - int getHorizontalBorderSize() const throw() { return horizontalBorderSize; } + /** Returns the average proportion of available CPU being spent inside the audio callbacks. - /** Returns the size of the vertical gap being left around the text. + Returns a value between 0 and 1.0 */ - int getVerticalBorderSize() const throw() { return verticalBorderSize; } + double getCpuUsage() const; - /** Makes this label "stick to" another component. + /** Enables or disables a midi input device. - This will cause the label to follow another component around, staying - either to its left or above it. + The list of devices can be obtained with the MidiInput::getDevices() method. - @param owner the component to follow - @param onLeft if true, the label will stay on the left of its component; if - false, it will stay above it. - */ - void attachToComponent (Component* owner, - const bool onLeft); + Any incoming messages from enabled input devices will be forwarded on to all the + listeners that have been registered with the addMidiInputCallback() method. They + can either register for messages from a particular device, or from just the + "default" midi input. - /** If this label has been attached to another component using attachToComponent, this - returns the other component. + Routing the midi input via an AudioDeviceManager means that when a listener + registers for the default midi input, this default device can be changed by the + manager without the listeners having to know about it or re-register. - Returns 0 if the label is not attached. + It also means that a listener can stay registered for a midi input that is disabled + or not present, so that when the input is re-enabled, the listener will start + receiving messages again. + + @see addMidiInputCallback, isMidiInputEnabled */ - Component* getAttachedComponent() const throw() { return ownerComponent; } + void setMidiInputEnabled (const String& midiInputDeviceName, + const bool enabled); - /** If the label is attached to the left of another component, this returns true. + /** Returns true if a given midi input device is being used. - Returns false if the label is above the other component. This is only relevent if - attachToComponent() has been called. + @see setMidiInputEnabled */ - bool isAttachedOnLeft() const throw() { return leftOfOwnerComp; } + bool isMidiInputEnabled (const String& midiInputDeviceName) const; - /** Specifies the minimum amount that the font can be squashed horizantally before it starts - using ellipsis. + /** Registers a listener for callbacks when midi events arrive from a midi input. - @see Graphics::drawFittedText + The device name can be empty to indicate that it wants events from whatever the + current "default" device is. Or it can be the name of one of the midi input devices + (see MidiInput::getDevices() for the names). + + Only devices which are enabled (see the setMidiInputEnabled() method) will have their + events forwarded on to listeners. */ - void setMinimumHorizontalScale (const float newScale); + void addMidiInputCallback (const String& midiInputDeviceName, + MidiInputCallback* callback); - float getMinimumHorizontalScale() const throw() { return minimumHorizontalScale; } + /** Removes a listener that was previously registered with addMidiInputCallback(). + */ + void removeMidiInputCallback (const String& midiInputDeviceName, + MidiInputCallback* callback); - /** Registers a listener that will be called when the label's text changes. */ - void addListener (LabelListener* const listener) throw(); + /** Sets a midi output device to use as the default. - /** Deregisters a previously-registered listener. */ - void removeListener (LabelListener* const listener) throw(); + The list of devices can be obtained with the MidiOutput::getDevices() method. - /** Makes the label turn into a TextEditor when clicked. + The specified device will be opened automatically and can be retrieved with the + getDefaultMidiOutput() method. - By default this is turned off. + Pass in an empty string to deselect all devices. For the default device, you + can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()]. - If turned on, then single- or double-clicking will turn the label into - an editor. If the user then changes the text, then the ChangeBroadcaster - base class will be used to send change messages to any listeners that - have registered. + @see getDefaultMidiOutput, getDefaultMidiOutputName + */ + void setDefaultMidiOutput (const String& deviceName); - If the user changes the text, the textWasEdited() method will be called - afterwards, and subclasses can override this if they need to do anything - special. + /** Returns the name of the default midi output. - @param editOnSingleClick if true, just clicking once on the label will start editing the text - @param editOnDoubleClick if true, a double-click is needed to start editing - @param lossOfFocusDiscardsChanges if true, clicking somewhere else while the text is being - edited will discard any changes; if false, then this will - commit the changes. - @see showEditor, setEditorColours, TextEditor + @see setDefaultMidiOutput, getDefaultMidiOutput */ - void setEditable (const bool editOnSingleClick, - const bool editOnDoubleClick = false, - const bool lossOfFocusDiscardsChanges = false) throw(); + const String getDefaultMidiOutputName() const throw() { return defaultMidiOutputName; } - /** Returns true if this option was set using setEditable(). */ - bool isEditableOnSingleClick() const throw() { return editSingleClick; } + /** Returns the current default midi output device. - /** Returns true if this option was set using setEditable(). */ - bool isEditableOnDoubleClick() const throw() { return editDoubleClick; } + If no device has been selected, or the device can't be opened, this will + return 0. - /** Returns true if this option has been set in a call to setEditable(). */ - bool doesLossOfFocusDiscardChanges() const throw() { return lossOfFocusDiscardsChanges; } + @see getDefaultMidiOutputName + */ + MidiOutput* getDefaultMidiOutput() const throw() { return defaultMidiOutput; } - /** Returns true if the user can edit this label's text. */ - bool isEditable() const throw() { return editSingleClick || editDoubleClick; } + /** Returns a list of the types of device supported. + */ + const OwnedArray & getAvailableDeviceTypes(); - /** Makes the editor appear as if the label had been clicked by the user. + /** Creates a list of available types. - @see textWasEdited, setEditable + This will add a set of new AudioIODeviceType objects to the specified list, to + represent each available types of device. + + You can override this if your app needs to do something specific, like avoid + using DirectSound devices, etc. */ - void showEditor(); + virtual void createAudioDeviceTypes (OwnedArray & types); - /** Hides the editor if it was being shown. + /** Plays a beep through the current audio device. - @param discardCurrentEditorContents if true, the label's text will be - reset to whatever it was before the editor - was shown; if false, the current contents of the - editor will be used to set the label's text - before it is hidden. + This is here to allow the audio setup UI panels to easily include a "test" + button so that the user can check where the audio is coming from. */ - void hideEditor (const bool discardCurrentEditorContents); - - /** Returns true if the editor is currently focused and active. */ - bool isBeingEdited() const throw(); + void playTestSound(); - juce_UseDebuggingNewOperator + /** Turns on level-measuring. -protected: - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - void mouseDoubleClick (const MouseEvent& e); - /** @internal */ - void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); - /** @internal */ - void componentParentHierarchyChanged (Component& component); - /** @internal */ - void componentVisibilityChanged (Component& component); - /** @internal */ - void inputAttemptWhenModal(); - /** @internal */ - void focusGained (FocusChangeType); - /** @internal */ - void enablementChanged(); - /** @internal */ - KeyboardFocusTraverser* createFocusTraverser(); - /** @internal */ - void textEditorTextChanged (TextEditor& editor); - /** @internal */ - void textEditorReturnKeyPressed (TextEditor& editor); - /** @internal */ - void textEditorEscapeKeyPressed (TextEditor& editor); - /** @internal */ - void textEditorFocusLost (TextEditor& editor); - /** @internal */ - void colourChanged(); + When enabled, the device manager will measure the peak input level + across all channels, and you can get this level by calling getCurrentInputLevel(). - /** Creates the TextEditor component that will be used when the user has clicked on the label. + This is mainly intended for audio setup UI panels to use to create a mic + level display, so that the user can check that they've selected the right + device. - Subclasses can override this if they need to customise this component in some way. + A simple filter is used to make the level decay smoothly, but this is + only intended for giving rough feedback, and not for any kind of accurate + measurement. */ - virtual TextEditor* createEditorComponent(); + void enableInputLevelMeasurement (const bool enableMeasurement); - /** Called after the user changes the text. - */ - virtual void textWasEdited(); + /** Returns the current input level. - /** Called when the text has been altered. - */ - virtual void textWasChanged(); + To use this, you must first enable it by calling enableInputLevelMeasurement(). - /** Called when the text editor has just appeared, due to a user click or other - focus change. + See enableInputLevelMeasurement() for more info. */ - virtual void editorShown (TextEditor* editorComponent); + double getCurrentInputLevel() const; - /** Called when the text editor is going to be deleted, after editing has finished. - */ - virtual void editorAboutToBeHidden (TextEditor* editorComponent); + juce_UseDebuggingNewOperator private: - String text; - Font font; - Justification justification; - TextEditor* editor; - SortedSet listeners; - Component* ownerComponent; - ComponentDeletionWatcher* deletionWatcher; - int horizontalBorderSize, verticalBorderSize; - float minimumHorizontalScale; - bool editSingleClick : 1; - bool editDoubleClick : 1; - bool lossOfFocusDiscardsChanges : 1; - bool leftOfOwnerComp : 1; - bool updateFromTextEditorContents(); - void callChangeListeners(); + OwnedArray availableDeviceTypes; + OwnedArray lastDeviceTypeConfigs; - Label (const Label&); - const Label& operator= (const Label&); -}; + AudioDeviceSetup currentSetup; + AudioIODevice* currentAudioDevice; + SortedSet callbacks; + int numInputChansNeeded, numOutputChansNeeded; + String currentDeviceType; + BitArray inputChannels, outputChannels; + XmlElement* lastExplicitSettings; + mutable bool listNeedsScanning; + bool useInputNames; + int inputLevelMeasurementEnabledCount; + double inputLevel; + AudioSampleBuffer* testSound; + int testSoundPosition; + AudioSampleBuffer tempBuffer; -#endif // __JUCE_LABEL_JUCEHEADER__ -/********* End of inlined file: juce_Label.h *********/ + StringArray midiInsFromXml; + OwnedArray enabledMidiInputs; + Array midiCallbacks; + Array midiCallbackDevices; + String defaultMidiOutputName; + MidiOutput* defaultMidiOutput; + CriticalSection audioCallbackLock, midiCallbackLock; -class ComboBox; + double cpuUsageMs, timeToCpuScale; -/** - A class for receiving events from a ComboBox. + class CallbackHandler : public AudioIODeviceCallback, + public MidiInputCallback + { + public: + AudioDeviceManager* owner; - You can register a ComboBoxListener with a ComboBox using the ComboBox::addListener() - method, and it will be called when the selected item in the box changes. + void audioDeviceIOCallback (const float** inputChannelData, + int totalNumInputChannels, + float** outputChannelData, + int totalNumOutputChannels, + int numSamples); - @see ComboBox::addListener, ComboBox::removeListener -*/ -class JUCE_API ComboBoxListener -{ -public: - /** Destructor. */ - virtual ~ComboBoxListener() {} + void audioDeviceAboutToStart (AudioIODevice*); - /** Called when a ComboBox has its selected item changed. - */ - virtual void comboBoxChanged (ComboBox* comboBoxThatHasChanged) = 0; -}; + void audioDeviceStopped(); -/** - A component that lets the user choose from a drop-down list of choices. + void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); + }; - The combo-box has a list of text strings, each with an associated id number, - that will be shown in the drop-down list when the user clicks on the component. + CallbackHandler callbackHandler; + friend class CallbackHandler; - The currently selected choice is displayed in the combo-box, and this can - either be read-only text, or editable. + void audioDeviceIOCallbackInt (const float** inputChannelData, + int totalNumInputChannels, + float** outputChannelData, + int totalNumOutputChannels, + int numSamples); + void audioDeviceAboutToStartInt (AudioIODevice* const device); + void audioDeviceStoppedInt(); - To find out when the user selects a different item or edits the text, you - can register a ComboBoxListener to receive callbacks. + void handleIncomingMidiMessageInt (MidiInput* source, const MidiMessage& message); - @see ComboBoxListener -*/ -class JUCE_API ComboBox : public Component, - public SettableTooltipClient, - private LabelListener, - private AsyncUpdater -{ -public: + const String restartDevice (int blockSizeToUse, double sampleRateToUse, + const BitArray& ins, const BitArray& outs); + void stopDevice(); - /** Creates a combo-box. + void updateXml(); - On construction, the text field will be empty, so you should call the - setSelectedId() or setText() method to choose the initial value before - displaying it. + void createDeviceTypesIfNeeded(); + void scanDevicesIfNeeded(); + void deleteCurrentDevice(); + double chooseBestSampleRate (double preferred) const; + void insertDefaultDeviceNames (AudioDeviceSetup& setup) const; - @param componentName the name to set for the component (see Component::setName()) - */ - ComboBox (const String& componentName); + AudioIODeviceType* findType (const String& inputName, const String& outputName); - /** Destructor. */ - ~ComboBox(); + AudioDeviceManager (const AudioDeviceManager&); + const AudioDeviceManager& operator= (const AudioDeviceManager&); +}; - /** Sets whether the test in the combo-box is editable. +#endif // __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_AudioDeviceManager.h *********/ - The default state for a new ComboBox is non-editable, and can only be changed - by choosing from the drop-down list. - */ - void setEditableText (const bool isEditable); +#endif +#ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__ - /** Returns true if the text is directly editable. - @see setEditableText - */ - bool isTextEditable() const throw(); +#endif +#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ - /** Sets the style of justification to be used for positioning the text. +#endif +#ifndef __JUCE_MIDIINPUT_JUCEHEADER__ - The default is Justification::centredLeft. The text is displayed using a - Label component inside the ComboBox. - */ - void setJustificationType (const Justification& justification) throw(); +#endif +#ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ - /** Returns the current justification for the text box. - @see setJustificationType - */ - const Justification getJustificationType() const throw(); +#endif +#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ - /** Adds an item to be shown in the drop-down list. +/********* Start of inlined file: juce_AudioDataConverters.h *********/ +#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +#define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ - @param newItemText the text of the item to show in the list - @param newItemId an associated ID number that can be set or retrieved - see - getSelectedId() and setSelectedId() - @see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId - */ - void addItem (const String& newItemText, - const int newItemId) throw(); +/** + A set of routines to convert buffers of 32-bit floating point data to and from + various integer formats. - /** Adds a separator line to the drop-down list. +*/ +class JUCE_API AudioDataConverters +{ +public: - This is like adding a separator to a popup menu. See PopupMenu::addSeparator(). - */ - void addSeparator() throw(); + static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); + static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 2); - /** Adds a heading to the drop-down list, so that you can group the items into - different sections. + static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); + static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 3); - The headings are indented slightly differently to set them apart from the - items on the list, and obviously can't be selected. You might want to add - separators between your sections too. + static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); + static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); - @see addItem, addSeparator - */ - void addSectionHeading (const String& headingName) throw(); + static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); + static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, const int destBytesPerSample = 4); - /** This allows items in the drop-down list to be selectively disabled. + static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); + static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 2); - When you add an item, it's enabled by default, but you can call this - method to change its status. + static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); + static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 3); - If you disable an item which is already selected, this won't change the - current selection - it just stops the user choosing that item from the list. - */ - void setItemEnabled (const int itemId, - const bool shouldBeEnabled) throw(); + static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); + static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); - /** Changes the text for an existing item. - */ - void changeItemText (const int itemId, - const String& newText) throw(); + static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); + static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, const int srcBytesPerSample = 4); - /** Removes all the items from the drop-down list. + enum DataFormat + { + int16LE, + int16BE, + int24LE, + int24BE, + int32LE, + int32BE, + float32LE, + float32BE, + }; - If this call causes the content to be cleared, then a change-message - will be broadcast unless dontSendChangeMessage is true. + static void convertFloatToFormat (const DataFormat destFormat, + const float* source, void* dest, int numSamples); - @see addItem, removeItem, getNumItems - */ - void clear (const bool dontSendChangeMessage = false); + static void convertFormatToFloat (const DataFormat sourceFormat, + const void* source, float* dest, int numSamples); - /** Returns the number of items that have been added to the list. + static void interleaveSamples (const float** source, float* dest, + const int numSamples, const int numChannels); - Note that this doesn't include headers or separators. - */ - int getNumItems() const throw(); + static void deinterleaveSamples (const float* source, float** dest, + const int numSamples, const int numChannels); +}; - /** Returns the text for one of the items in the list. +#endif // __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ +/********* End of inlined file: juce_AudioDataConverters.h *********/ - Note that this doesn't include headers or separators. +#endif +#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ - @param index the item's index from 0 to (getNumItems() - 1) - */ - const String getItemText (const int index) const throw(); +#endif +#ifndef __JUCE_IIRFILTER_JUCEHEADER__ - /** Returns the ID for one of the items in the list. +#endif +#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ - Note that this doesn't include headers or separators. +#endif +#ifndef __JUCE_MIDIFILE_JUCEHEADER__ - @param index the item's index from 0 to (getNumItems() - 1) - */ - int getItemId (const int index) const throw(); +/********* Start of inlined file: juce_MidiFile.h *********/ +#ifndef __JUCE_MIDIFILE_JUCEHEADER__ +#define __JUCE_MIDIFILE_JUCEHEADER__ - /** Returns the ID of the item that's currently shown in the box. +/********* Start of inlined file: juce_MidiMessageSequence.h *********/ +#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ +#define __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ - If no item is selected, or if the text is editable and the user - has entered something which isn't one of the items in the list, then - this will return 0. +/** + A sequence of timestamped midi messages. - @see setSelectedId, getSelectedItemIndex, getText - */ - int getSelectedId() const throw(); + This allows the sequence to be manipulated, and also to be read from and + written to a standard midi file. - /** Sets one of the items to be the current selection. + @see MidiMessage, MidiFile +*/ +class JUCE_API MidiMessageSequence +{ +public: - This will set the ComboBox's text to that of the item that matches - this ID. + /** Creates an empty midi sequence object. */ + MidiMessageSequence(); - @param newItemId the new item to select - @param dontSendChangeMessage if set to true, this method won't trigger a - change notification - @see getSelectedId, setSelectedItemIndex, setText - */ - void setSelectedId (const int newItemId, - const bool dontSendChangeMessage = false) throw(); + /** Creates a copy of another sequence. */ + MidiMessageSequence (const MidiMessageSequence& other); - /** Returns the index of the item that's currently shown in the box. + /** Replaces this sequence with another one. */ + const MidiMessageSequence& operator= (const MidiMessageSequence& other); - If no item is selected, or if the text is editable and the user - has entered something which isn't one of the items in the list, then - this will return -1. + /** Destructor. */ + ~MidiMessageSequence(); - @see setSelectedItemIndex, getSelectedId, getText + /** Structure used to hold midi events in the sequence. + + These structures act as 'handles' on the events as they are moved about in + the list, and make it quick to find the matching note-offs for note-on events. + + @see MidiMessageSequence::getEventPointer */ - int getSelectedItemIndex() const throw(); + class MidiEventHolder + { + public: - /** Sets one of the items to be the current selection. + /** Destructor. */ + ~MidiEventHolder(); - This will set the ComboBox's text to that of the item at the given - index in the list. + /** The message itself, whose timestamp is used to specify the event's time. + */ + MidiMessage message; - @param newItemIndex the new item to select - @param dontSendChangeMessage if set to true, this method won't trigger a - change notification - @see getSelectedItemIndex, setSelectedId, setText + /** The matching note-off event (if this is a note-on event). + + If this isn't a note-on, this pointer will be null. + + Use the MidiMessageSequence::updateMatchedPairs() method to keep these + note-offs up-to-date after events have been moved around in the sequence + or deleted. + */ + MidiEventHolder* noteOffObject; + + juce_UseDebuggingNewOperator + + private: + friend class MidiMessageSequence; + MidiEventHolder (const MidiMessage& message); + }; + + /** Clears the sequence. */ + void clear(); + + /** Returns the number of events in the sequence. */ + int getNumEvents() const; + + /** Returns a pointer to one of the events. */ + MidiEventHolder* getEventPointer (const int index) const; + + /** Returns the time of the note-up that matches the note-on at this index. + + If the event at this index isn't a note-on, it'll just return 0. + + @see MidiMessageSequence::MidiEventHolder::noteOffObject */ - void setSelectedItemIndex (const int newItemIndex, - const bool dontSendChangeMessage = false) throw(); + double getTimeOfMatchingKeyUp (const int index) const; - /** Returns the text that is currently shown in the combo-box's text field. + /** Returns the index of the note-up that matches the note-on at this index. - If the ComboBox has editable text, then this text may have been edited - by the user; otherwise it will be one of the items from the list, or - possibly an empty string if nothing was selected. + If the event at this index isn't a note-on, it'll just return -1. - @see setText, getSelectedId, getSelectedItemIndex + @see MidiMessageSequence::MidiEventHolder::noteOffObject */ - const String getText() const throw(); + int getIndexOfMatchingKeyUp (const int index) const; - /** Sets the contents of the combo-box's text field. + /** Returns the index of an event. */ + int getIndexOf (MidiEventHolder* const event) const; - The text passed-in will be set as the current text regardless of whether - it is one of the items in the list. If the current text isn't one of the - items, then getSelectedId() will return -1, otherwise it wil return - the approriate ID. + /** Returns the index of the first event on or after the given timestamp. - @param newText the text to select - @param dontSendChangeMessage if set to true, this method won't trigger a - change notification - @see getText + If the time is beyond the end of the sequence, this will return the + number of events. */ - void setText (const String& newText, - const bool dontSendChangeMessage = false) throw(); + int getNextIndexAtTime (const double timeStamp) const; - /** Programmatically opens the text editor to allow the user to edit the current item. + /** Returns the timestamp of the first event in the sequence. - This is the same effect as when the box is clicked-on. - @see Label::showEditor(); + @see getEndTime */ - void showEditor(); + double getStartTime() const; - /** Registers a listener that will be called when the box's content changes. */ - void addListener (ComboBoxListener* const listener) throw(); + /** Returns the timestamp of the last event in the sequence. - /** Deregisters a previously-registered listener. */ - void removeListener (ComboBoxListener* const listener) throw(); + @see getStartTime + */ + double getEndTime() const; - /** Sets a message to display when there is no item currently selected. + /** Returns the timestamp of the event at a given index. - @see getTextWhenNothingSelected + If the index is out-of-range, this will return 0.0 */ - void setTextWhenNothingSelected (const String& newMessage) throw(); + double getEventTime (const int index) const; - /** Returns the text that is shown when no item is selected. + /** Inserts a midi message into the sequence. - @see setTextWhenNothingSelected + The index at which the new message gets inserted will depend on its timestamp, + because the sequence is kept sorted. + + Remember to call updateMatchedPairs() after adding note-on events. + + @param newMessage the new message to add (an internal copy will be made) + @param timeAdjustment an optional value to add to the timestamp of the message + that will be inserted + @see updateMatchedPairs */ - const String getTextWhenNothingSelected() const throw(); + void addEvent (const MidiMessage& newMessage, + double timeAdjustment = 0); - /** Sets the message to show when there are no items in the list, and the user clicks - on the drop-down box. + /** Deletes one of the events in the sequence. - By default it just says "no choices", but this lets you change it to something more - meaningful. + Remember to call updateMatchedPairs() after removing events. + + @param index the index of the event to delete + @param deleteMatchingNoteUp whether to also remove the matching note-off + if the event you're removing is a note-on */ - void setTextWhenNoChoicesAvailable (const String& newMessage) throw(); + void deleteEvent (const int index, + const bool deleteMatchingNoteUp); - /** Returns the text shown when no items have been added to the list. - @see setTextWhenNoChoicesAvailable + /** Merges another sequence into this one. + + Remember to call updateMatchedPairs() after using this method. + + @param other the sequence to add from + @param timeAdjustmentDelta an amount to add to the timestamps of the midi events + as they are read from the other sequence + @param firstAllowableDestTime events will not be added if their time is earlier + than this time. (This is after their time has been adjusted + by the timeAdjustmentDelta) + @param endOfAllowableDestTimes events will not be added if their time is equal to + or greater than this time. (This is after their time has + been adjusted by the timeAdjustmentDelta) */ - const String getTextWhenNoChoicesAvailable() const throw(); + void addSequence (const MidiMessageSequence& other, + double timeAdjustmentDelta, + double firstAllowableDestTime, + double endOfAllowableDestTimes); - /** Gives the ComboBox a tooltip. */ - void setTooltip (const String& newTooltip); + /** Makes sure all the note-on and note-off pairs are up-to-date. - /** A set of colour IDs to use to change the colour of various aspects of the combo box. + Call this after moving messages about or deleting/adding messages, and it + will scan the list and make sure all the note-offs in the MidiEventHolder + structures are pointing at the correct ones. + */ + void updateMatchedPairs(); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** Copies all the messages for a particular midi channel to another sequence. - To change the colours of the menu that pops up + @param channelNumberToExtract the midi channel to look for, in the range 1 to 16 + @param destSequence the sequence that the chosen events should be copied to + @param alsoIncludeMetaEvents if true, any meta-events (which don't apply to a specific + channel) will also be copied across. + @see extractSysExMessages + */ + void extractMidiChannelMessages (const int channelNumberToExtract, + MidiMessageSequence& destSequence, + const bool alsoIncludeMetaEvents) const; - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + /** Copies all midi sys-ex messages to another sequence. + + @param destSequence this is the sequence to which any sys-exes in this sequence + will be added + @see extractMidiChannelMessages */ - enum ColourIds - { - backgroundColourId = 0x1000b00, /**< The background colour to fill the box with. */ - textColourId = 0x1000a00, /**< The colour for the text in the box. */ - outlineColourId = 0x1000c00, /**< The colour for an outline around the box. */ - buttonColourId = 0x1000d00, /**< The base colour for the button (a LookAndFeel class will probably use variations on this). */ - arrowColourId = 0x1000e00, /**< The colour for the arrow shape that pops up the menu */ - }; + void extractSysExMessages (MidiMessageSequence& destSequence) const; - /** @internal */ - void labelTextChanged (Label*); - /** @internal */ - void enablementChanged(); - /** @internal */ - void colourChanged(); - /** @internal */ - void focusGained (Component::FocusChangeType cause); - /** @internal */ - void focusLost (Component::FocusChangeType cause); - /** @internal */ - void handleAsyncUpdate(); - /** @internal */ - const String getTooltip() { return label->getTooltip(); } - /** @internal */ - void mouseDown (const MouseEvent&); - /** @internal */ - void mouseDrag (const MouseEvent&); - /** @internal */ - void mouseUp (const MouseEvent&); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - void paint (Graphics&); - /** @internal */ - void resized(); - /** @internal */ - bool keyStateChanged (const bool isKeyDown); - /** @internal */ - bool keyPressed (const KeyPress&); + /** Removes any messages in this sequence that have a specific midi channel. - juce_UseDebuggingNewOperator + @param channelNumberToRemove the midi channel to look for, in the range 1 to 16 + */ + void deleteMidiChannelMessages (const int channelNumberToRemove); -private: - struct ItemInfo - { - String name; - int itemId; - bool isEnabled : 1, isHeading : 1; + /** Removes any sys-ex messages from this sequence. + */ + void deleteSysExMessages(); - bool isSeparator() const throw(); - bool isRealItem() const throw(); - }; + /** Adds an offset to the timestamps of all events in the sequence. - OwnedArray items; - int currentIndex; - bool isButtonDown; - bool separatorPending; - bool menuActive; - SortedSet listeners; - Label* label; - String textWhenNothingSelected, noChoicesMessage; + @param deltaTime the amount to add to each timestamp. + */ + void addTimeToMessages (const double deltaTime); - void showPopup(); + /** Scans through the sequence to determine the state of any midi controllers at + a given time. - ItemInfo* getItemForId (const int itemId) const throw(); - ItemInfo* getItemForIndex (const int index) const throw(); + This will create a sequence of midi controller changes that can be + used to set all midi controllers to the state they would be in at the + specified time within this sequence. - ComboBox (const ComboBox&); - const ComboBox& operator= (const ComboBox&); -}; + As well as controllers, it will also recreate the midi program number + and pitch bend position. -#endif // __JUCE_COMBOBOX_JUCEHEADER__ -/********* End of inlined file: juce_ComboBox.h *********/ + @param channelNumber the midi channel to look for, in the range 1 to 16. Controllers + for other channels will be ignored. + @param time the time at which you want to find out the state - there are + no explicit units for this time measurement, it's the same units + as used for the timestamps of the messages + @param resultMessages an array to which midi controller-change messages will be added. This + will be the minimum number of controller changes to recreate the + state at the required time. + */ + void createControllerUpdatesForTime (const int channelNumber, + const double time, + OwnedArray& resultMessages); -/** - Manages the state of some audio and midi i/o devices. + juce_UseDebuggingNewOperator - This class keeps tracks of a currently-selected audio device, through - with which it continuously streams data from an audio callback, as well as - one or more midi inputs. + /** @internal */ + static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, + const MidiMessageSequence::MidiEventHolder* const second) throw(); - The idea is that your application will create one global instance of this object, - and let it take care of creating and deleting specific types of audio devices - internally. So when the device is changed, your callbacks will just keep running - without having to worry about this. +private: - The manager can save and reload all of its device settings as XML, which - makes it very easy for you to save and reload the audio setup of your - application. + friend class MidiComparator; + friend class MidiFile; + OwnedArray list; - And to make it easy to let the user change its settings, there's a component - to do just that - the AudioDeviceSelectorComponent class, which contains a set of - device selection/sample-rate/latency controls. + void sort(); +}; - To use an AudioDeviceManager, create one, and use initialise() to set it up. Then - call addAudioCallback() to register your audio callback with it, and use that to process - your audio data. +#endif // __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ +/********* End of inlined file: juce_MidiMessageSequence.h *********/ - The manager also acts as a handy hub for incoming midi messages, allowing a - listener to register for messages from either a specific midi device, or from whatever - the current default midi input device is. The listener then doesn't have to worry about - re-registering with different midi devices if they are changed or deleted. +/** + Reads/writes standard midi format files. - And yet another neat trick is that amount of CPU time being used is measured and - available with the getCpuUsage() method. + To read a midi file, create a MidiFile object and call its readFrom() method. You + can then get the individual midi tracks from it using the getTrack() method. - The AudioDeviceManager is a ChangeBroadcaster, and will send a change message to - listeners whenever one of its settings is changed. + To write a file, create a MidiFile object, add some MidiMessageSequence objects + to it using the addTrack() method, and then call its writeTo() method to stream + it out. - @see AudioDeviceSelectorComponent, AudioIODevice, AudioIODeviceType + @see MidiMessageSequence */ -class JUCE_API AudioDeviceManager : public ChangeBroadcaster +class JUCE_API MidiFile { public: - /** Creates a default AudioDeviceManager. - - Initially no audio device will be selected. You should call the initialise() method - and register an audio callback with setAudioCallback() before it'll be able to - actually make any noise. + /** Creates an empty MidiFile object. */ - AudioDeviceManager(); + MidiFile() throw(); /** Destructor. */ - ~AudioDeviceManager(); + ~MidiFile() throw(); - /** - This structure holds a set of properties describing the current audio setup. + /** Returns the number of tracks in the file. - @see AudioDeviceManager::setAudioDeviceSetup() + @see getTrack, addTrack */ - struct JUCE_API AudioDeviceSetup - { - AudioDeviceSetup(); - bool operator== (const AudioDeviceSetup& other) const; + int getNumTracks() const throw(); - /** The name of the audio device used for output. - The name has to be one of the ones listed by the AudioDeviceManager's currently - selected device type. - This may be the same as the input device. - */ - String outputDeviceName; + /** Returns a pointer to one of the tracks in the file. - /** The name of the audio device used for input. - This may be the same as the output device. - */ - String inputDeviceName; + @returns a pointer to the track, or 0 if the index is out-of-range + @see getNumTracks, addTrack + */ + const MidiMessageSequence* getTrack (const int index) const throw(); - /** The current sample rate. - This rate is used for both the input and output devices. - */ - double sampleRate; + /** Adds a midi track to the file. - /** The buffer size, in samples. - This buffer size is used for both the input and output devices. - */ - int bufferSize; + This will make its own internal copy of the sequence that is passed-in. - /** The set of active input channels. - The bits that are set in this array indicate the channels of the - input device that are active. - */ - BitArray inputChannels; + @see getNumTracks, getTrack + */ + void addTrack (const MidiMessageSequence& trackSequence) throw(); - /** If this is true, it indicates that the inputChannels array - should be ignored, and instead, the device's default channels - should be used. - */ - bool useDefaultInputChannels; + /** Removes all midi tracks from the file. - /** The set of active output channels. - The bits that are set in this array indicate the channels of the - input device that are active. - */ - BitArray outputChannels; + @see getNumTracks + */ + void clear() throw(); - /** If this is true, it indicates that the outputChannels array - should be ignored, and instead, the device's default channels - should be used. - */ - bool useDefaultOutputChannels; - }; + /** Returns the raw time format code that will be written to a stream. - /** Opens a set of audio devices ready for use. + After reading a midi file, this method will return the time-format that + was read from the file's header. It can be changed using the setTicksPerQuarterNote() + or setSmpteTimeFormat() methods. - This will attempt to open either a default audio device, or one that was - previously saved as XML. + If the value returned is positive, it indicates the number of midi ticks + per quarter-note - see setTicksPerQuarterNote(). - @param numInputChannelsNeeded a minimum number of input channels needed - by your app. - @param numOutputChannelsNeeded a minimum number of output channels to open - @param savedState either a previously-saved state that was produced - by createStateXml(), or 0 if you want the manager - to choose the best device to open. - @param selectDefaultDeviceOnFailure if true, then if the device specified in the XML - fails to open, then a default device will be used - instead. If false, then on failure, no device is - opened. - @param preferredDefaultDeviceName if this is not empty, and there's a device with this - name, then that will be used as the default device - (assuming that there wasn't one specified in the XML). - The string can actually be a simple wildcard, containing "*" - and "?" characters - @param preferredSetupOptions if this is non-null, the structure will be used as the - set of preferred settings when opening the device. If you - use this parameter, the preferredDefaultDeviceName - field will be ignored - - @returns an error message if anything went wrong, or an empty string if it worked ok. + It it's negative, the upper byte indicates the frames-per-second (but negative), and + the lower byte is the number of ticks per frame - see setSmpteTimeFormat(). */ - const String initialise (const int numInputChannelsNeeded, - const int numOutputChannelsNeeded, - const XmlElement* const savedState, - const bool selectDefaultDeviceOnFailure, - const String& preferredDefaultDeviceName = String::empty, - const AudioDeviceSetup* preferredSetupOptions = 0); - - /** Returns some XML representing the current state of the manager. + short getTimeFormat() const throw(); - This stores the current device, its samplerate, block size, etc, and - can be restored later with initialise(). - */ - XmlElement* createStateXml() const; + /** Sets the time format to use when this file is written to a stream. - /** Returns the current device properties that are in use. + If this is called, the file will be written as bars/beats using the + specified resolution, rather than SMPTE absolute times, as would be + used if setSmpteTimeFormat() had been called instead. - @see setAudioDeviceSetup + @param ticksPerQuarterNote e.g. 96, 960 + @see setSmpteTimeFormat */ - void getAudioDeviceSetup (AudioDeviceSetup& setup); - - /** Changes the current device or its settings. + void setTicksPerQuarterNote (const int ticksPerQuarterNote) throw(); - If you want to change a device property, like the current sample rate or - block size, you can call getAudioDeviceSetup() to retrieve the current - settings, then tweak the appropriate fields in the AudioDeviceSetup structure, - and pass it back into this method to apply the new settings. + /** Sets the time format to use when this file is written to a stream. - @param newSetup the settings that you'd like to use - @param treatAsChosenDevice if this is true and if the device opens correctly, these new - settings will be taken as having been explicitly chosen by the - user, and the next time createStateXml() is called, these settings - will be returned. If it's false, then the device is treated as a - temporary or default device, and a call to createStateXml() will - return either the last settings that were made with treatAsChosenDevice - as true, or the last XML settings that were passed into initialise(). - @returns an error message if anything went wrong, or an empty string if it worked ok. + If this is called, the file will be written using absolute times, rather + than bars/beats as would be the case if setTicksPerBeat() had been called + instead. - @see getAudioDeviceSetup + @param framesPerSecond must be 24, 25, 29 or 30 + @param subframeResolution the sub-second resolution, e.g. 4 (midi time code), + 8, 10, 80 (SMPTE bit resolution), or 100. For millisecond + timing, setSmpteTimeFormat (25, 40) + @see setTicksPerBeat */ - const String setAudioDeviceSetup (const AudioDeviceSetup& newSetup, - const bool treatAsChosenDevice); + void setSmpteTimeFormat (const int framesPerSecond, + const int subframeResolution) throw(); - /** Returns the currently-active audio device. */ - AudioIODevice* getCurrentAudioDevice() const throw() { return currentAudioDevice; } + /** Makes a list of all the tempo-change meta-events from all tracks in the midi file. - /** Returns the type of audio device currently in use. - @see setCurrentAudioDeviceType - */ - const String getCurrentAudioDeviceType() const throw() { return currentDeviceType; } + Useful for finding the positions of all the tempo changes in a file. - /** Returns the currently active audio device type object. - Don't keep a copy of this pointer - it's owned by the device manager and could - change at any time. + @param tempoChangeEvents a list to which all the events will be added */ - AudioIODeviceType* getCurrentDeviceTypeObject() const; + void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const; - /** Changes the class of audio device being used. + /** Makes a list of all the time-signature meta-events from all tracks in the midi file. - This switches between, e.g. ASIO and DirectSound. On the Mac you probably won't ever call - this because there's only one type: CoreAudio. + Useful for finding the positions of all the tempo changes in a file. - For a list of types, see getAvailableDeviceTypes(). + @param timeSigEvents a list to which all the events will be added */ - void setCurrentAudioDeviceType (const String& type, - const bool treatAsChosenDevice); + void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const; - /** Closes the currently-open device. + /** Returns the latest timestamp in any of the tracks. - You can call restartLastAudioDevice() later to reopen it in the same state - that it was just in. + (Useful for finding the length of the file). */ - void closeAudioDevice(); + double getLastTimestamp() const; - /** Tries to reload the last audio device that was running. + /** Reads a midi file format stream. - Note that this only reloads the last device that was running before - closeAudioDevice() was called - it doesn't reload any kind of saved-state, - and can only be called after a device has been opened with SetAudioDevice(). + After calling this, you can get the tracks that were read from the file by using the + getNumTracks() and getTrack() methods. - If a device is already open, this call will do nothing. + The timestamps of the midi events in the tracks will represent their positions in + terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds() + method. + + @returns true if the stream was read successfully */ - void restartLastAudioDevice(); + bool readFrom (InputStream& sourceStream); - /** Registers an audio callback to be used. + /** Writes the midi tracks as a standard midi file. - The manager will redirect callbacks from whatever audio device is currently - in use to all registered callback objects. If more than one callback is - active, they will all be given the same input data, and their outputs will - be summed. + @returns true if the operation succeeded. + */ + bool writeTo (OutputStream& destStream); - If necessary, this method will invoke audioDeviceAboutToStart() on the callback - object before returning. + /** Converts the timestamp of all the midi events from midi ticks to seconds. - To remove a callback, use removeAudioCallback(). + This will use the midi time format and tempo/time signature info in the + tracks to convert all the timestamps to absolute values in seconds. */ - void addAudioCallback (AudioIODeviceCallback* newCallback); - - /** Deregisters a previously added callback. + void convertTimestampTicksToSeconds(); - If necessary, this method will invoke audioDeviceStopped() on the callback - object before returning. + juce_UseDebuggingNewOperator - @see addAudioCallback - */ - void removeAudioCallback (AudioIODeviceCallback* callback); + /** @internal */ + static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, + const MidiMessageSequence::MidiEventHolder* const second) throw(); - /** Returns the average proportion of available CPU being spent inside the audio callbacks. +private: + MidiMessageSequence* tracks [128]; + short numTracks, timeFormat; - Returns a value between 0 and 1.0 - */ - double getCpuUsage() const; + MidiFile (const MidiFile&); + const MidiFile& operator= (const MidiFile&); - /** Enables or disables a midi input device. + void readNextTrack (const char* data, int size); + void writeTrack (OutputStream& mainOut, const int trackNum); +}; - The list of devices can be obtained with the MidiInput::getDevices() method. +#endif // __JUCE_MIDIFILE_JUCEHEADER__ +/********* End of inlined file: juce_MidiFile.h *********/ - Any incoming messages from enabled input devices will be forwarded on to all the - listeners that have been registered with the addMidiInputCallback() method. They - can either register for messages from a particular device, or from just the - "default" midi input. +#endif +#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ - Routing the midi input via an AudioDeviceManager means that when a listener - registers for the default midi input, this default device can be changed by the - manager without the listeners having to know about it or re-register. +/********* Start of inlined file: juce_MidiKeyboardState.h *********/ +#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ +#define __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ - It also means that a listener can stay registered for a midi input that is disabled - or not present, so that when the input is re-enabled, the listener will start - receiving messages again. +class MidiKeyboardState; - @see addMidiInputCallback, isMidiInputEnabled - */ - void setMidiInputEnabled (const String& midiInputDeviceName, - const bool enabled); +/** + Receives events from a MidiKeyboardState object. - /** Returns true if a given midi input device is being used. + @see MidiKeyboardState +*/ +class JUCE_API MidiKeyboardStateListener +{ +public: - @see setMidiInputEnabled - */ - bool isMidiInputEnabled (const String& midiInputDeviceName) const; + MidiKeyboardStateListener() throw() {} + virtual ~MidiKeyboardStateListener() {} - /** Registers a listener for callbacks when midi events arrive from a midi input. + /** Called when one of the MidiKeyboardState's keys is pressed. - The device name can be empty to indicate that it wants events from whatever the - current "default" device is. Or it can be the name of one of the midi input devices - (see MidiInput::getDevices() for the names). + This will be called synchronously when the state is either processing a + buffer in its MidiKeyboardState::processNextMidiBuffer() method, or + when a note is being played with its MidiKeyboardState::noteOn() method. - Only devices which are enabled (see the setMidiInputEnabled() method) will have their - events forwarded on to listeners. + Note that this callback could happen from an audio callback thread, so be + careful not to block, and avoid any UI activity in the callback. */ - void addMidiInputCallback (const String& midiInputDeviceName, - MidiInputCallback* callback); + virtual void handleNoteOn (MidiKeyboardState* source, + int midiChannel, int midiNoteNumber, float velocity) = 0; - /** Removes a listener that was previously registered with addMidiInputCallback(). - */ - void removeMidiInputCallback (const String& midiInputDeviceName, - MidiInputCallback* callback); + /** Called when one of the MidiKeyboardState's keys is released. - /** Sets a midi output device to use as the default. + This will be called synchronously when the state is either processing a + buffer in its MidiKeyboardState::processNextMidiBuffer() method, or + when a note is being played with its MidiKeyboardState::noteOff() method. - The list of devices can be obtained with the MidiOutput::getDevices() method. + Note that this callback could happen from an audio callback thread, so be + careful not to block, and avoid any UI activity in the callback. + */ + virtual void handleNoteOff (MidiKeyboardState* source, + int midiChannel, int midiNoteNumber) = 0; +}; - The specified device will be opened automatically and can be retrieved with the - getDefaultMidiOutput() method. +/** + Represents a piano keyboard, keeping track of which keys are currently pressed. - Pass in an empty string to deselect all devices. For the default device, you - can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()]. + This object can parse a stream of midi events, using them to update its idea + of which keys are pressed for each individiual midi channel. - @see getDefaultMidiOutput, getDefaultMidiOutputName - */ - void setDefaultMidiOutput (const String& deviceName); + When keys go up or down, it can broadcast these events to listener objects. - /** Returns the name of the default midi output. + It also allows key up/down events to be triggered with its noteOn() and noteOff() + methods, and midi messages for these events will be merged into the + midi stream that gets processed by processNextMidiBuffer(). +*/ +class JUCE_API MidiKeyboardState +{ +public: - @see setDefaultMidiOutput, getDefaultMidiOutput - */ - const String getDefaultMidiOutputName() const throw() { return defaultMidiOutputName; } + MidiKeyboardState(); + ~MidiKeyboardState(); - /** Returns the current default midi output device. + /** Resets the state of the object. - If no device has been selected, or the device can't be opened, this will - return 0. + All internal data for all the channels is reset, but no events are sent as a + result. - @see getDefaultMidiOutputName + If you want to release any keys that are currently down, and to send out note-up + midi messages for this, use the allNotesOff() method instead. */ - MidiOutput* getDefaultMidiOutput() const throw() { return defaultMidiOutput; } + void reset(); - /** Returns a list of the types of device supported. + /** Returns true if the given midi key is currently held down for the given midi channel. + + The channel number must be between 1 and 16. If you want to see if any notes are + on for a range of channels, use the isNoteOnForChannels() method. */ - const OwnedArray & getAvailableDeviceTypes(); + bool isNoteOn (const int midiChannel, const int midiNoteNumber) const throw(); - /** Creates a list of available types. + /** Returns true if the given midi key is currently held down on any of a set of midi channels. - This will add a set of new AudioIODeviceType objects to the specified list, to - represent each available types of device. + The channel mask has a bit set for each midi channel you want to test for - bit + 0 = midi channel 1, bit 1 = midi channel 2, etc. - You can override this if your app needs to do something specific, like avoid - using DirectSound devices, etc. + If a note is on for at least one of the specified channels, this returns true. */ - virtual void createAudioDeviceTypes (OwnedArray & types); + bool isNoteOnForChannels (const int midiChannelMask, const int midiNoteNumber) const throw(); - /** Plays a beep through the current audio device. + /** Turns a specified note on. - This is here to allow the audio setup UI panels to easily include a "test" - button so that the user can check where the audio is coming from. + This will cause a suitable midi note-on event to be injected into the midi buffer during the + next call to processNextMidiBuffer(). + + It will also trigger a synchronous callback to the listeners to tell them that the key has + gone down. */ - void playTestSound(); + void noteOn (const int midiChannel, const int midiNoteNumber, const float velocity); - /** Turns on level-measuring. + /** Turns a specified note off. - When enabled, the device manager will measure the peak input level - across all channels, and you can get this level by calling getCurrentInputLevel(). + This will cause a suitable midi note-off event to be injected into the midi buffer during the + next call to processNextMidiBuffer(). - This is mainly intended for audio setup UI panels to use to create a mic - level display, so that the user can check that they've selected the right - device. + It will also trigger a synchronous callback to the listeners to tell them that the key has + gone up. - A simple filter is used to make the level decay smoothly, but this is - only intended for giving rough feedback, and not for any kind of accurate - measurement. + But if the note isn't acutally down for the given channel, this method will in fact do nothing. */ - void enableInputLevelMeasurement (const bool enableMeasurement); + void noteOff (const int midiChannel, const int midiNoteNumber); - /** Returns the current input level. + /** This will turn off any currently-down notes for the given midi channel. - To use this, you must first enable it by calling enableInputLevelMeasurement(). + If you pass 0 for the midi channel, it will in fact turn off all notes on all channels. - See enableInputLevelMeasurement() for more info. + Calling this method will make calls to noteOff(), so can trigger synchronous callbacks + and events being added to the midi stream. */ - double getCurrentInputLevel() const; - - juce_UseDebuggingNewOperator - -private: - - OwnedArray availableDeviceTypes; - OwnedArray lastDeviceTypeConfigs; + void allNotesOff (const int midiChannel); - AudioDeviceSetup currentSetup; - AudioIODevice* currentAudioDevice; - SortedSet callbacks; - int numInputChansNeeded, numOutputChansNeeded; - String currentDeviceType; - BitArray inputChannels, outputChannels; - XmlElement* lastExplicitSettings; - mutable bool listNeedsScanning; - bool useInputNames; - int inputLevelMeasurementEnabledCount; - double inputLevel; - AudioSampleBuffer* testSound; - int testSoundPosition; - AudioSampleBuffer tempBuffer; + /** Looks at a key-up/down event and uses it to update the state of this object. - StringArray midiInsFromXml; - OwnedArray enabledMidiInputs; - Array midiCallbacks; - Array midiCallbackDevices; - String defaultMidiOutputName; - MidiOutput* defaultMidiOutput; - CriticalSection audioCallbackLock, midiCallbackLock; + To process a buffer full of midi messages, use the processNextMidiBuffer() method + instead. + */ + void processNextMidiEvent (const MidiMessage& message); - double cpuUsageMs, timeToCpuScale; + /** Scans a midi stream for up/down events and adds its own events to it. - class CallbackHandler : public AudioIODeviceCallback, - public MidiInputCallback - { - public: - AudioDeviceManager* owner; + This will look for any up/down events and use them to update the internal state, + synchronously making suitable callbacks to the listeners. - void audioDeviceIOCallback (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples); + If injectIndirectEvents is true, then midi events to produce the recent noteOn() + and noteOff() calls will be added into the buffer. - void audioDeviceAboutToStart (AudioIODevice*); + Only the section of the buffer whose timestamps are between startSample and + (startSample + numSamples) will be affected, and any events added will be placed + between these times. - void audioDeviceStopped(); + If you're going to use this method, you'll need to keep calling it regularly for + it to work satisfactorily. - void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); - }; + To process a single midi event at a time, use the processNextMidiEvent() method + instead. + */ + void processNextMidiBuffer (MidiBuffer& buffer, + const int startSample, + const int numSamples, + const bool injectIndirectEvents); - CallbackHandler callbackHandler; - friend class CallbackHandler; + /** Registers a listener for callbacks when keys go up or down. - void audioDeviceIOCallbackInt (const float** inputChannelData, - int totalNumInputChannels, - float** outputChannelData, - int totalNumOutputChannels, - int numSamples); - void audioDeviceAboutToStartInt (AudioIODevice* const device); - void audioDeviceStoppedInt(); + @see removeListener + */ + void addListener (MidiKeyboardStateListener* const listener) throw(); - void handleIncomingMidiMessageInt (MidiInput* source, const MidiMessage& message); + /** Deregisters a listener. - const String restartDevice (int blockSizeToUse, double sampleRateToUse, - const BitArray& ins, const BitArray& outs); - void stopDevice(); + @see addListener + */ + void removeListener (MidiKeyboardStateListener* const listener) throw(); - void updateXml(); + juce_UseDebuggingNewOperator - void createDeviceTypesIfNeeded(); - void scanDevicesIfNeeded(); - void deleteCurrentDevice(); - double chooseBestSampleRate (double preferred) const; - void insertDefaultDeviceNames (AudioDeviceSetup& setup) const; +private: + CriticalSection lock; + uint16 noteStates [128]; + MidiBuffer eventsToAdd; + VoidArray listeners; - AudioIODeviceType* findType (const String& inputName, const String& outputName); + void noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity); + void noteOffInternal (const int midiChannel, const int midiNoteNumber); - AudioDeviceManager (const AudioDeviceManager&); - const AudioDeviceManager& operator= (const AudioDeviceManager&); + MidiKeyboardState (const MidiKeyboardState&); + const MidiKeyboardState& operator= (const MidiKeyboardState&); }; -#endif // __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_AudioDeviceManager.h *********/ - -#endif -#ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__ - -#endif -#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ - -#endif -#ifndef __JUCE_MIDIINPUT_JUCEHEADER__ +#endif // __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ +/********* End of inlined file: juce_MidiKeyboardState.h *********/ #endif -#ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ +#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ #endif -#ifndef __JUCE_SAMPLER_JUCEHEADER__ - -/********* Start of inlined file: juce_Sampler.h *********/ -#ifndef __JUCE_SAMPLER_JUCEHEADER__ -#define __JUCE_SAMPLER_JUCEHEADER__ +#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ -/********* Start of inlined file: juce_Synthesiser.h *********/ -#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ -#define __JUCE_SYNTHESISER_JUCEHEADER__ +/********* Start of inlined file: juce_MidiMessageCollector.h *********/ +#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ +#define __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ /** - Describes one of the sounds that a Synthesiser can play. - - A synthesiser can contain one or more sounds, and a sound can choose which - midi notes and channels can trigger it. + Collects incoming realtime MIDI messages and turns them into blocks suitable for + processing by a block-based audio callback. - The SynthesiserSound is a passive class that just describes what the sound is - - the actual audio rendering for a sound is done by a SynthesiserVoice. This allows - more than one SynthesiserVoice to play the same sound at the same time. + The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback + so it can easily use a midi input or keyboard component as its source. - @see Synthesiser, SynthesiserVoice + @see MidiMessage, MidiInput */ -class JUCE_API SynthesiserSound : public ReferenceCountedObject +class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener, + public MidiInputCallback { -protected: +public: - SynthesiserSound(); + /** Creates a MidiMessageCollector. */ + MidiMessageCollector(); -public: /** Destructor. */ - virtual ~SynthesiserSound(); + ~MidiMessageCollector(); - /** Returns true if this sound should be played when a given midi note is pressed. + /** Clears any messages from the queue. - The Synthesiser will use this information when deciding which sounds to trigger - for a given note. + You need to call this method before starting to use the collector, so that + it knows the correct sample rate to use. */ - virtual bool appliesToNote (const int midiNoteNumber) = 0; + void reset (const double sampleRate); - /** Returns true if the sound should be triggered by midi events on a given channel. + /** Takes an incoming real-time message and adds it to the queue. - The Synthesiser will use this information when deciding which sounds to trigger - for a given note. - */ - virtual bool appliesToChannel (const int midiChannel) = 0; + The message's timestamp is taken, and it will be ready for retrieval as part + of the block returned by the next call to removeNextBlockOfMessages(). - /** + This method is fully thread-safe when overlapping calls are made with + removeNextBlockOfMessages(). */ - typedef ReferenceCountedObjectPtr Ptr; + void addMessageToQueue (const MidiMessage& message); - juce_UseDebuggingNewOperator -}; + /** Removes all the pending messages from the queue as a buffer. -/** - Represents a voice that a Synthesiser can use to play a SynthesiserSound. + This will also correct the messages' timestamps to make sure they're in + the range 0 to numSamples - 1. - A voice plays a single sound at a time, and a synthesiser holds an array of - voices so that it can play polyphonically. + This call should be made regularly by something like an audio processing + callback, because the time that it happens is used in calculating the + midi event positions. - @see Synthesiser, SynthesiserSound -*/ -class JUCE_API SynthesiserVoice -{ -public: + This method is fully thread-safe when overlapping calls are made with + addMessageToQueue(). + */ + void removeNextBlockOfMessages (MidiBuffer& destBuffer, + const int numSamples); - /** Creates a voice. */ - SynthesiserVoice(); + /** @internal */ + void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity); + /** @internal */ + void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber); + /** @internal */ + void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); - /** Destructor. */ - virtual ~SynthesiserVoice(); + juce_UseDebuggingNewOperator - /** Returns the midi note that this voice is currently playing. +private: + double lastCallbackTime; + CriticalSection midiCallbackLock; + MidiBuffer incomingMessages; + double sampleRate; - Returns a value less than 0 if no note is playing. - */ - int getCurrentlyPlayingNote() const throw() { return currentlyPlayingNote; } + MidiMessageCollector (const MidiMessageCollector&); + const MidiMessageCollector& operator= (const MidiMessageCollector&); +}; - /** Returns the sound that this voice is currently playing. +#endif // __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ +/********* End of inlined file: juce_MidiMessageCollector.h *********/ - Returns 0 if it's not playing. - */ - const SynthesiserSound::Ptr getCurrentlyPlayingSound() const throw() { return currentlyPlayingSound; } +#endif +#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ - /** Must return true if this voice object is capable of playing the given sound. +#endif +#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ - If there are different classes of sound, and different classes of voice, a voice can - choose which ones it wants to take on. +/********* Start of inlined file: juce_AudioUnitPluginFormat.h *********/ +#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ +#define __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ - A typical implementation of this method may just return true if there's only one type - of voice and sound, or it might check the type of the sound object passed-in and - see if it's one that it understands. - */ - virtual bool canPlaySound (SynthesiserSound* sound) = 0; +/********* Start of inlined file: juce_AudioPluginFormat.h *********/ +#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ +#define __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ - /** Called to start a new note. +/********* Start of inlined file: juce_AudioPluginInstance.h *********/ +#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ +#define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ - This will be called during the rendering callback, so must be fast and thread-safe. - */ - virtual void startNote (const int midiNoteNumber, - const float velocity, - SynthesiserSound* sound, - const int currentPitchWheelPosition) = 0; +/********* Start of inlined file: juce_AudioProcessor.h *********/ +#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSOR_JUCEHEADER__ - /** Called to stop a note. +/********* Start of inlined file: juce_AudioProcessorEditor.h *********/ +#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ - This will be called during the rendering callback, so must be fast and thread-safe. +class AudioProcessor; - If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all - sound immediately, and must call clearCurrentNote() to reset the state of this voice - and allow the synth to reassign it another sound. +/** + Base class for the component that acts as the GUI for an AudioProcessor. - If allowTailOff is true and the voice decides to do a tail-off, then it's allowed to - begin fading out its sound, and it can stop playing until it's finished. As soon as it - finishes playing (during the rendering callback), it must make sure that it calls - clearCurrentNote(). - */ - virtual void stopNote (const bool allowTailOff) = 0; + Derive your editor component from this class, and create an instance of it + by overriding the AudioProcessor::createEditor() method. - /** Called to let the voice know that the pitch wheel has been moved. + @see AudioProcessor, GenericAudioProcessorEditor +*/ +class JUCE_API AudioProcessorEditor : public Component +{ +protected: - This will be called during the rendering callback, so must be fast and thread-safe. + /** Creates an editor for the specified processor. */ - virtual void pitchWheelMoved (const int newValue) = 0; - - /** Called to let the voice know that a midi controller has been moved. + AudioProcessorEditor (AudioProcessor* const owner); - This will be called during the rendering callback, so must be fast and thread-safe. - */ - virtual void controllerMoved (const int controllerNumber, - const int newValue) = 0; +public: + /** Destructor. */ + ~AudioProcessorEditor(); - /** Renders the next block of data for this voice. + /** Returns a pointer to the processor that this editor represents. */ + AudioProcessor* getAudioProcessor() const throw() { return owner; } - The output audio data must be added to the current contents of the buffer provided. - Only the region of the buffer between startSample and (startSample + numSamples) - should be altered by this method. +private: - If the voice is currently silent, it should just return without doing anything. + AudioProcessor* const owner; +}; - If the sound that the voice is playing finishes during the course of this rendered - block, it must call clearCurrentNote(), to tell the synthesiser that it has finished. +#endif // __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ +/********* End of inlined file: juce_AudioProcessorEditor.h *********/ - The size of the blocks that are rendered can change each time it is called, and may - involve rendering as little as 1 sample at a time. In between rendering callbacks, - the voice's methods will be called to tell it about note and controller events. - */ - virtual void renderNextBlock (AudioSampleBuffer& outputBuffer, - int startSample, - int numSamples) = 0; +/********* Start of inlined file: juce_AudioProcessorListener.h *********/ +#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ - /** Returns true if the voice is currently playing a sound which is mapped to the given - midi channel. +class AudioProcessor; - If it's not currently playing, this will return false. - */ - bool isPlayingChannel (const int midiChannel) const; +/** + Base class for listeners that want to know about changes to an AudioProcessor. - /** Changes the voice's reference sample rate. + Use AudioProcessor::addListener() to register your listener with an AudioProcessor. - The rate is set so that subclasses know the output rate and can set their pitch - accordingly. + @see AudioProcessor +*/ +class JUCE_API AudioProcessorListener +{ +public: - This method is called by the synth, and subclasses can access the current rate with - the currentSampleRate member. - */ - void setCurrentPlaybackSampleRate (const double newRate); + /** Destructor. */ + virtual ~AudioProcessorListener() {} - juce_UseDebuggingNewOperator + /** Receives a callback when a parameter is changed. -protected: + IMPORTANT NOTE: this will be called synchronously when a parameter changes, and + many audio processors will change their parameter during their audio callback. + This means that not only has your handler code got to be completely thread-safe, + but it's also got to be VERY fast, and avoid blocking. If you need to handle + this event on your message thread, use this callback to trigger an AsyncUpdater + or ChangeBroadcaster which you can respond to on the message thread. + */ + virtual void audioProcessorParameterChanged (AudioProcessor* processor, + int parameterIndex, + float newValue) = 0; - /** Returns the current target sample rate at which rendering is being done. + /** Called to indicate that something else in the plugin has changed, like its + program, number of parameters, etc. - This is available for subclasses so they can pitch things correctly. + IMPORTANT NOTE: this will be called synchronously, and many audio processors will + call it during their audio callback. This means that not only has your handler code + got to be completely thread-safe, but it's also got to be VERY fast, and avoid + blocking. If you need to handle this event on your message thread, use this callback + to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the + message thread. */ - double getSampleRate() const throw() { return currentSampleRate; } + virtual void audioProcessorChanged (AudioProcessor* processor) = 0; - /** Resets the state of this voice after a sound has finished playing. + /** Indicates that a parameter change gesture has started. - The subclass must call this when it finishes playing a note and becomes available - to play new ones. + E.g. if the user is dragging a slider, this would be called when they first + press the mouse button, and audioProcessorParameterChangeGestureEnd would be + called when they release it. - It must either call it in the stopNote() method, or if the voice is tailing off, - then it should call it later during the renderNextBlock method, as soon as it - finishes its tail-off. + IMPORTANT NOTE: this will be called synchronously, and many audio processors will + call it during their audio callback. This means that not only has your handler code + got to be completely thread-safe, but it's also got to be VERY fast, and avoid + blocking. If you need to handle this event on your message thread, use this callback + to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the + message thread. - It can also be called at any time during the render callback if the sound happens - to have finished, e.g. if it's playing a sample and the sample finishes. + @see audioProcessorParameterChangeGestureEnd */ - void clearCurrentNote(); + virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor, + int parameterIndex); -private: + /** Indicates that a parameter change gesture has finished. - friend class Synthesiser; + E.g. if the user is dragging a slider, this would be called when they release + the mouse button. - double currentSampleRate; - int currentlyPlayingNote; - uint32 noteOnTime; - SynthesiserSound::Ptr currentlyPlayingSound; -}; + IMPORTANT NOTE: this will be called synchronously, and many audio processors will + call it during their audio callback. This means that not only has your handler code + got to be completely thread-safe, but it's also got to be VERY fast, and avoid + blocking. If you need to handle this event on your message thread, use this callback + to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the + message thread. -/** - Base class for a musical device that can play sounds. + @see audioPluginParameterChangeGestureStart + */ + virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor, + int parameterIndex); +}; - To create a synthesiser, you'll need to create a subclass of SynthesiserSound - to describe each sound available to your synth, and a subclass of SynthesiserVoice - which can play back one of these sounds. +#endif // __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_AudioProcessorListener.h *********/ - Then you can use the addVoice() and addSound() methods to give the synthesiser a - set of sounds, and a set of voices it can use to play them. If you only give it - one voice it will be monophonic - the more voices it has, the more polyphony it'll - have available. +/********* Start of inlined file: juce_AudioPlayHead.h *********/ +#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ +#define __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ - Then repeatedly call the renderNextBlock() method to produce the audio. Any midi - events that go in will be scanned for note on/off messages, and these are used to - start and stop the voices playing the appropriate sounds. +/** + A subclass of AudioPlayHead can supply information about the position and + status of a moving play head during audio playback. - While it's playing, you can also cause notes to be triggered by calling the noteOn(), - noteOff() and other controller methods. + One of these can be supplied to an AudioProcessor object so that it can find + out about the position of the audio that it is rendering. - Before rendering, be sure to call the setCurrentPlaybackSampleRate() to tell it - what the target playback rate is. This value is passed on to the voices so that - they can pitch their output correctly. + @see AudioProcessor::setPlayHead, AudioProcessor::getPlayHead */ -class JUCE_API Synthesiser +class JUCE_API AudioPlayHead { +protected: + + AudioPlayHead() {} + public: + virtual ~AudioPlayHead() {} - /** Creates a new synthesiser. + /** Frame rate types. */ + enum FrameRateType + { + fps24 = 0, + fps25 = 1, + fps2997 = 2, + fps30 = 3, + fps2997drop = 4, + fps30drop = 5, + fpsUnknown = 99 + }; - You'll need to add some sounds and voices before it'll make any sound.. + /** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method. */ - Synthesiser(); + struct CurrentPositionInfo + { + /** The tempo in BPM */ + double bpm; - /** Destructor. */ - virtual ~Synthesiser(); + /** Time signature numerator, e.g. the 3 of a 3/4 time sig */ + int timeSigNumerator; + /** Time signature denominator, e.g. the 4 of a 3/4 time sig */ + int timeSigDenominator; - /** Deletes all voices. */ - void clearVoices(); + /** The current play position, in seconds from the start of the edit. */ + double timeInSeconds; - /** Returns the number of voices that have been added. */ - int getNumVoices() const throw() { return voices.size(); } + /** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */ + double editOriginTime; - /** Returns one of the voices that have been added. */ - SynthesiserVoice* getVoice (const int index) const throw(); + /** The current play position in pulses-per-quarter-note. - /** Adds a new voice to the synth. + This is the number of quarter notes since the edit start. + */ + double ppqPosition; - All the voices should be the same class of object and are treated equally. + /** The position of the start of the last bar, in pulses-per-quarter-note. - The object passed in will be managed by the synthesiser, which will delete - it later on when no longer needed. The caller should not retain a pointer to the - voice. - */ - void addVoice (SynthesiserVoice* const newVoice); + This is the number of quarter notes from the start of the edit to the + start of the current bar. - /** Deletes one of the voices. */ - void removeVoice (const int index); + Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If + it's not available, the value will be 0. + */ + double ppqPositionOfLastBarStart; - /** Deletes all sounds. */ - void clearSounds(); + /** The video frame rate, if applicable. */ + FrameRateType frameRate; - /** Returns the number of sounds that have been added to the synth. */ - int getNumSounds() const throw() { return sounds.size(); } + /** True if the transport is currently playing. */ + bool isPlaying; - /** Returns one of the sounds. */ - SynthesiserSound* getSound (const int index) const throw() { return sounds [index]; } + /** True if the transport is currently recording. - /** Adds a new sound to the synthesiser. + (When isRecording is true, then isPlaying will also be true). + */ + bool isRecording; + }; - The object passed in is reference counted, so will be deleted when it is removed - from the synthesiser, and when no voices are still using it. + /** Fills-in the given structure with details about the transport's + position at the start of the current processing block. */ - void addSound (const SynthesiserSound::Ptr& newSound); + virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0; +}; - /** Removes and deletes one of the sounds. */ - void removeSound (const int index); +#endif // __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ +/********* End of inlined file: juce_AudioPlayHead.h *********/ - /** If set to true, then the synth will try to take over an existing voice if - it runs out and needs to play another note. +/** + Base class for audio processing filters or plugins. - The value of this boolean is passed into findFreeVoice(), so the result will - depend on the implementation of this method. - */ - void setNoteStealingEnabled (const bool shouldStealNotes); + This is intended to act as a base class of audio filter that is general enough to + be wrapped as a VST, AU, RTAS, etc, or used internally. - /** Returns true if note-stealing is enabled. - @see setNoteStealingEnabled - */ - bool isNoteStealingEnabled() const throw() { return shouldStealNotes; } + It is also used by the plugin hosting code as the wrapper around an instance + of a loaded plugin. - /** Triggers a note-on event. + Derive your filter class from this base class, and if you're building a plugin, + you should implement a global function called createPluginFilter() which creates + and returns a new instance of your subclass. +*/ +class JUCE_API AudioProcessor +{ +protected: - The default method here will find all the sounds that want to be triggered by - this note/channel. For each sound, it'll try to find a free voice, and use the - voice to start playing the sound. + /** Constructor. - Subclasses might want to override this if they need a more complex algorithm. + You can also do your initialisation tasks in the initialiseFilterInfo() + call, which will be made after this object has been created. + */ + AudioProcessor(); - This method will be called automatically according to the midi data passed into - renderNextBlock(), but may be called explicitly too. +public: + /** Destructor. */ + virtual ~AudioProcessor(); + + /** Returns the name of this processor. */ - virtual void noteOn (const int midiChannel, - const int midiNoteNumber, - const float velocity); + virtual const String getName() const = 0; - /** Triggers a note-off event. + /** Called before playback starts, to let the filter prepare itself. - This will turn off any voices that are playing a sound for the given note/channel. + The sample rate is the target sample rate, and will remain constant until + playback stops. - If allowTailOff is true, the voices will be allowed to fade out the notes gracefully - (if they can do). If this is false, the notes will all be cut off immediately. + The estimatedSamplesPerBlock value is a HINT about the typical number of + samples that will be processed for each callback, but isn't any kind + of guarantee. The actual block sizes that the host uses may be different + each time the callback happens, and may be more or less than this value. + */ + virtual void prepareToPlay (double sampleRate, + int estimatedSamplesPerBlock) = 0; - This method will be called automatically according to the midi data passed into - renderNextBlock(), but may be called explicitly too. + /** Called after playback has stopped, to let the filter free up any resources it + no longer needs. */ - virtual void noteOff (const int midiChannel, - const int midiNoteNumber, - const bool allowTailOff); + virtual void releaseResources() = 0; - /** Turns off all notes. + /** Renders the next block. - This will turn off any voices that are playing a sound on the given midi channel. + When this method is called, the buffer contains a number of channels which is + at least as great as the maximum number of input and output channels that + this filter is using. It will be filled with the filter's input data and + should be replaced with the filter's output. - If midiChannel is 0 or less, then all voices will be turned off, regardless of - which channel they're playing. + So for example if your filter has 2 input channels and 4 output channels, then + the buffer will contain 4 channels, the first two being filled with the + input data. Your filter should read these, do its processing, and replace + the contents of all 4 channels with its output. - If allowTailOff is true, the voices will be allowed to fade out the notes gracefully - (if they can do). If this is false, the notes will all be cut off immediately. + Or if your filter has 5 inputs and 2 outputs, the buffer will have 5 channels, + all filled with data, and your filter should overwrite the first 2 of these + with its output. But be VERY careful not to write anything to the last 3 + channels, as these might be mapped to memory that the host assumes is read-only! - This method will be called automatically according to the midi data passed into - renderNextBlock(), but may be called explicitly too. - */ - virtual void allNotesOff (const int midiChannel, - const bool allowTailOff); + Note that if you have more outputs than inputs, then only those channels that + correspond to an input channel are guaranteed to contain sensible data - e.g. + in the case of 2 inputs and 4 outputs, the first two channels contain the input, + but the last two channels may contain garbage, so you should be careful not to + let this pass through without being overwritten or cleared. - /** Sends a pitch-wheel message. + Also note that the buffer may have more channels than are strictly necessary, + but your should only read/write from the ones that your filter is supposed to + be using. - This will send a pitch-wheel message to any voices that are playing sounds on - the given midi channel. + The number of samples in these buffers is NOT guaranteed to be the same for every + callback, and may be more or less than the estimated value given to prepareToPlay(). + Your code must be able to cope with variable-sized blocks, or you're going to get + clicks and crashes! - This method will be called automatically according to the midi data passed into - renderNextBlock(), but may be called explicitly too. + If the filter is receiving a midi input, then the midiMessages array will be filled + with the midi messages for this block. Each message's timestamp will indicate the + message's time, as a number of samples from the start of the block. - @param midiChannel the midi channel for the event - @param wheelValue the wheel position, from 0 to 0x3fff, as returned by MidiMessage::getPitchWheelValue() - */ - virtual void handlePitchWheel (const int midiChannel, - const int wheelValue); + Any messages left in the midi buffer when this method has finished are assumed to + be the filter's midi output. This means that your filter should be careful to + clear any incoming messages from the array if it doesn't want them to be passed-on. - /** Sends a midi controller message. + Be very careful about what you do in this callback - it's going to be called by + the audio thread, so any kind of interaction with the UI is absolutely + out of the question. If you change a parameter in here and need to tell your UI to + update itself, the best way is probably to inherit from a ChangeBroadcaster, let + the UI components register as listeners, and then call sendChangeMessage() inside the + processBlock() method to send out an asynchronous message. You could also use + the AsyncUpdater class in a similar way. + */ + virtual void processBlock (AudioSampleBuffer& buffer, + MidiBuffer& midiMessages) = 0; - This will send a midi controller message to any voices that are playing sounds on - the given midi channel. + /** Returns the current AudioPlayHead object that should be used to find + out the state and position of the playhead. - This method will be called automatically according to the midi data passed into - renderNextBlock(), but may be called explicitly too. + You can call this from your processBlock() method, and use the AudioPlayHead + object to get the details about the time of the start of the block currently + being processed. - @param midiChannel the midi channel for the event - @param controllerNumber the midi controller type, as returned by MidiMessage::getControllerNumber() - @param controllerValue the midi controller value, between 0 and 127, as returned by MidiMessage::getControllerValue() + If the host hasn't supplied a playhead object, this will return 0. */ - virtual void handleController (const int midiChannel, - const int controllerNumber, - const int controllerValue); + AudioPlayHead* getPlayHead() const throw() { return playHead; } - /** Tells the synthesiser what the sample rate is for the audio it's being used to - render. + /** Returns the current sample rate. - This value is propagated to the voices so that they can use it to render the correct - pitches. + This can be called from your processBlock() method - it's not guaranteed + to be valid at any other time, and may return 0 if it's unknown. */ - void setCurrentPlaybackSampleRate (const double sampleRate); + double getSampleRate() const throw() { return sampleRate; } - /** Creates the next block of audio output. + /** Returns the current typical block size that is being used. - This will process the next numSamples of data from all the voices, and add that output - to the audio block supplied, starting from the offset specified. Note that the - data will be added to the current contents of the buffer, so you should clear it - before calling this method if necessary. + This can be called from your processBlock() method - it's not guaranteed + to be valid at any other time. - The midi events in the inputMidi buffer are parsed for note and controller events, - and these are used to trigger the voices. Note that the startSample offset applies - both to the audio output buffer and the midi input buffer, so any midi events - with timestamps outside the specified region will be ignored. + Remember it's not the ONLY block size that may be used when calling + processBlock, it's just the normal one. The actual block sizes used may be + larger or smaller than this, and will vary between successive calls. */ - void renderNextBlock (AudioSampleBuffer& outputAudio, - const MidiBuffer& inputMidi, - int startSample, - int numSamples); + int getBlockSize() const throw() { return blockSize; } - juce_UseDebuggingNewOperator + /** Returns the number of input channels that the host will be sending the filter. -protected: + If writing a plugin, your JucePluginCharacteristics.h file should specify the + number of channels that your filter would prefer to have, and this method lets + you know how many the host is actually using. - /** This is used to control access to the rendering callback and the note trigger methods. */ - CriticalSection lock; + Note that this method is only valid during or after the prepareToPlay() + method call. Until that point, the number of channels will be unknown. + */ + int getNumInputChannels() const throw() { return numInputChannels; } - OwnedArray voices; - ReferenceCountedArray sounds; + /** Returns the number of output channels that the host will be sending the filter. - /** The last pitch-wheel values for each midi channel. */ - int lastPitchWheelValues [16]; + If writing a plugin, your JucePluginCharacteristics.h file should specify the + number of channels that your filter would prefer to have, and this method lets + you know how many the host is actually using. - /** Searches through the voices to find one that's not currently playing, and which - can play the given sound. + Note that this method is only valid during or after the prepareToPlay() + method call. Until that point, the number of channels will be unknown. + */ + int getNumOutputChannels() const throw() { return numOutputChannels; } - Returns 0 if all voices are busy and stealing isn't enabled. + /** Returns the name of one of the input channels, as returned by the host. - This can be overridden to implement custom voice-stealing algorithms. + The host might not supply very useful names for channels, and this might be + something like "1", "2", "left", "right", etc. */ - virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay, - const bool stealIfNoneAvailable) const; + virtual const String getInputChannelName (const int channelIndex) const = 0; - /** Starts a specified voice playing a particular sound. + /** Returns the name of one of the output channels, as returned by the host. - You'll probably never need to call this, it's used internally by noteOn(), but - may be needed by subclasses for custom behaviours. + The host might not supply very useful names for channels, and this might be + something like "1", "2", "left", "right", etc. */ - void startVoice (SynthesiserVoice* const voice, - SynthesiserSound* const sound, - const int midiChannel, - const int midiNoteNumber, - const float velocity); + virtual const String getOutputChannelName (const int channelIndex) const = 0; - /** xxx Temporary method here to cause a compiler error - note the new parameters for this method. */ - int findFreeVoice (const bool) const { return 0; } + /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ + virtual bool isInputChannelStereoPair (int index) const = 0; -private: - double sampleRate; - uint32 lastNoteOnCounter; - bool shouldStealNotes; + /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ + virtual bool isOutputChannelStereoPair (int index) const = 0; - Synthesiser (const Synthesiser&); - const Synthesiser& operator= (const Synthesiser&); -}; + /** This returns the number of samples delay that the filter imposes on the audio + passing through it. -#endif // __JUCE_SYNTHESISER_JUCEHEADER__ -/********* End of inlined file: juce_Synthesiser.h *********/ + The host will call this to find the latency - the filter itself should set this value + by calling setLatencySamples() as soon as it can during its initialisation. + */ + int getLatencySamples() const throw() { return latencySamples; } -/** - A subclass of SynthesiserSound that represents a sampled audio clip. + /** The filter should call this to set the number of samples delay that it introduces. - This is a pretty basic sampler, and just attempts to load the whole audio stream - into memory. + The filter should call this as soon as it can during initialisation, and can call it + later if the value changes. + */ + void setLatencySamples (const int newLatency); - To use it, create a Synthesiser, add some SamplerVoice objects to it, then - give it some SampledSound objects to play. + /** Returns true if the processor wants midi messages. */ + virtual bool acceptsMidi() const = 0; - @see SamplerVoice, Synthesiser, SynthesiserSound -*/ -class JUCE_API SamplerSound : public SynthesiserSound -{ -public: + /** Returns true if the processor produces midi messages. */ + virtual bool producesMidi() const = 0; - /** Creates a sampled sound from an audio reader. + /** This returns a critical section that will automatically be locked while the host + is calling the processBlock() method. - This will attempt to load the audio from the source into memory and store - it in this object. + Use it from your UI or other threads to lock access to variables that are used + by the process callback, but obviously be careful not to keep it locked for + too long, because that could cause stuttering playback. If you need to do something + that'll take a long time and need the processing to stop while it happens, use the + suspendProcessing() method instead. - @param name a name for the sample - @param source the audio to load. This object can be safely deleted by the - caller after this constructor returns - @param midiNotes the set of midi keys that this sound should be played on. This - is used by the SynthesiserSound::appliesToNote() method - @param midiNoteForNormalPitch the midi note at which the sample should be played - with its natural rate. All other notes will be pitched - up or down relative to this one - @param attackTimeSecs the attack (fade-in) time, in seconds - @param releaseTimeSecs the decay (fade-out) time, in seconds - @param maxSampleLengthSeconds a maximum length of audio to read from the audio - source, in seconds + @see suspendProcessing */ - SamplerSound (const String& name, - AudioFormatReader& source, - const BitArray& midiNotes, - const int midiNoteForNormalPitch, - const double attackTimeSecs, - const double releaseTimeSecs, - const double maxSampleLengthSeconds); + const CriticalSection& getCallbackLock() const throw() { return callbackLock; } - /** Destructor. */ - ~SamplerSound(); + /** Enables and disables the processing callback. - /** Returns the sample's name */ - const String& getName() const throw() { return name; } + If you need to do something time-consuming on a thread and would like to make sure + the audio processing callback doesn't happen until you've finished, use this + to disable the callback and re-enable it again afterwards. - /** Returns the audio sample data. - This could be 0 if there was a problem loading it. - */ - AudioSampleBuffer* getAudioData() const throw() { return data; } + E.g. + @code + void loadNewPatch() + { + suspendProcessing (true); - bool appliesToNote (const int midiNoteNumber); - bool appliesToChannel (const int midiChannel); + ..do something that takes ages.. - juce_UseDebuggingNewOperator + suspendProcessing (false); + } + @endcode -private: - friend class SamplerVoice; + If the host tries to make an audio callback while processing is suspended, the + filter will return an empty buffer, but won't block the audio thread like it would + do if you use the getCallbackLock() critical section to synchronise access. - String name; - AudioSampleBuffer* data; - double sourceSampleRate; - BitArray midiNotes; - int length, attackSamples, releaseSamples; - int midiRootNote; -}; + If you're going to use this, your processBlock() method must call isSuspended() and + check whether it's suspended or not. If it is, then it should skip doing any real + processing, either emitting silence or passing the input through unchanged. -/** - A subclass of SynthesiserVoice that can play a SamplerSound. + @see getCallbackLock + */ + void suspendProcessing (const bool shouldBeSuspended); - To use it, create a Synthesiser, add some SamplerVoice objects to it, then - give it some SampledSound objects to play. + /** Returns true if processing is currently suspended. + @see suspendProcessing + */ + bool isSuspended() const throw() { return suspended; } - @see SamplerSound, Synthesiser, SynthesiserVoice -*/ -class JUCE_API SamplerVoice : public SynthesiserVoice -{ -public: + /** A plugin can override this to be told when it should reset any playing voices. - /** Creates a SamplerVoice. + The default implementation does nothing, but a host may call this to tell the + plugin that it should stop any tails or sounds that have been left running. */ - SamplerVoice(); + virtual void reset(); - /** Destructor. */ - ~SamplerVoice(); + /** Returns true if the processor is being run in an offline mode for rendering. - bool canPlaySound (SynthesiserSound* sound); + If the processor is being run live on realtime signals, this returns false. + If the mode is unknown, this will assume it's realtime and return false. - void startNote (const int midiNoteNumber, - const float velocity, - SynthesiserSound* sound, - const int currentPitchWheelPosition); + This value may be unreliable until the prepareToPlay() method has been called, + and could change each time prepareToPlay() is called. - void stopNote (const bool allowTailOff); + @see setNonRealtime() + */ + bool isNonRealtime() const throw() { return nonRealtime; } - void pitchWheelMoved (const int newValue); - void controllerMoved (const int controllerNumber, - const int newValue); + /** Called by the host to tell this processor whether it's being used in a non-realime + capacity for offline rendering or bouncing. - void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples); + Whatever value is passed-in will be + */ + void setNonRealtime (const bool isNonRealtime) throw(); - juce_UseDebuggingNewOperator + /** Creates the filter's UI. -private: - double pitchRatio; - double sourceSamplePosition; - float lgain, rgain, attackReleaseLevel, attackDelta, releaseDelta; - bool isInAttack, isInRelease; -}; + This can return 0 if you want a UI-less filter, in which case the host may create + a generic UI that lets the user twiddle the parameters directly. -#endif // __JUCE_SAMPLER_JUCEHEADER__ -/********* End of inlined file: juce_Sampler.h *********/ + If you do want to pass back a component, the component should be created and set to + the correct size before returning it. -#endif -#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ + Remember not to do anything silly like allowing your filter to keep a pointer to + the component that gets created - it could be deleted later without any warning, which + would make your pointer into a dangler. Use the getActiveEditor() method instead. -#endif -#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ + The correct way to handle the connection between an editor component and its + filter is to use something like a ChangeBroadcaster so that the editor can + register itself as a listener, and be told when a change occurs. This lets them + safely unregister themselves when they are deleted. -/********* Start of inlined file: juce_AudioUnitPluginFormat.h *********/ -#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ -#define __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ + Here are a few things to bear in mind when writing an editor: -#if JUCE_PLUGINHOST_AU && JUCE_MAC + - Initially there won't be an editor, until the user opens one, or they might + not open one at all. Your filter mustn't rely on it being there. + - An editor object may be deleted and a replacement one created again at any time. + - It's safe to assume that an editor will be deleted before its filter. + */ + virtual AudioProcessorEditor* createEditor() = 0; -/** - Implements a plugin format manager for AudioUnits. -*/ -class JUCE_API AudioUnitPluginFormat : public AudioPluginFormat -{ -public: + /** Returns the active editor, if there is one. - AudioUnitPluginFormat(); - ~AudioUnitPluginFormat(); + Bear in mind this can return 0, even if an editor has previously been + opened. + */ + AudioProcessorEditor* getActiveEditor() const throw() { return activeEditor; } - const String getName() const { return "AudioUnit"; } - void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); - AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); - bool fileMightContainThisPluginType (const String& fileOrIdentifier); - const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); - const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); - bool doesPluginStillExist (const PluginDescription& desc); - const FileSearchPath getDefaultLocationsToSearch(); + /** Returns the active editor, or if there isn't one, it will create one. - juce_UseDebuggingNewOperator + This may call createEditor() internally to create the component. + */ + AudioProcessorEditor* createEditorIfNeeded(); -private: - AudioUnitPluginFormat (const AudioUnitPluginFormat&); - const AudioUnitPluginFormat& operator= (const AudioUnitPluginFormat&); -}; + /** This must return the correct value immediately after the object has been + created, and mustn't change the number of parameters later. + */ + virtual int getNumParameters() = 0; -#endif + /** Returns the name of a particular parameter. */ + virtual const String getParameterName (int parameterIndex) = 0; -#endif // __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_AudioUnitPluginFormat.h *********/ + /** Called by the host to find out the value of one of the filter's parameters. -#endif -#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ + The host will expect the value returned to be between 0 and 1.0. -/********* Start of inlined file: juce_DirectXPluginFormat.h *********/ -#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ -#define __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ + This could be called quite frequently, so try to make your code efficient. + It's also likely to be called by non-UI threads, so the code in here should + be thread-aware. + */ + virtual float getParameter (int parameterIndex) = 0; -#if JUCE_PLUGINHOST_DX && JUCE_WIN32 + /** Returns the value of a parameter as a text string. */ + virtual const String getParameterText (int parameterIndex) = 0; -// Sorry, this file is just a placeholder at the moment!... + /** The host will call this method to change the value of one of the filter's parameters. -/** - Implements a plugin format manager for DirectX plugins. -*/ -class JUCE_API DirectXPluginFormat : public AudioPluginFormat -{ -public: + The host may call this at any time, including during the audio processing + callback, so the filter has to process this very fast and avoid blocking. - DirectXPluginFormat(); - ~DirectXPluginFormat(); + If you want to set the value of a parameter internally, e.g. from your + editor component, then don't call this directly - instead, use the + setParameterNotifyingHost() method, which will also send a message to + the host telling it about the change. If the message isn't sent, the host + won't be able to automate your parameters properly. - const String getName() const { return "DirectX"; } - void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); - AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); - bool fileMightContainThisPluginType (const String& fileOrIdentifier); - const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } - const FileSearchPath getDefaultLocationsToSearch(); + The value passed will be between 0 and 1.0. + */ + virtual void setParameter (int parameterIndex, + float newValue) = 0; - juce_UseDebuggingNewOperator + /** Your filter can call this when it needs to change one of its parameters. -private: - DirectXPluginFormat (const DirectXPluginFormat&); - const DirectXPluginFormat& operator= (const DirectXPluginFormat&); -}; + This could happen when the editor or some other internal operation changes + a parameter. This method will call the setParameter() method to change the + value, and will then send a message to the host telling it about the change. -#endif + Note that to make sure the host correctly handles automation, you should call + the beginParameterChangeGesture() and endParameterChangeGesture() methods to + tell the host when the user has started and stopped changing the parameter. + */ + void setParameterNotifyingHost (int parameterIndex, + float newValue); -#endif // __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_DirectXPluginFormat.h *********/ + /** Returns true if the host can automate this parameter. -#endif -#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ + By default, this returns true for all parameters. + */ + virtual bool isParameterAutomatable (int parameterIndex) const; -/********* Start of inlined file: juce_LADSPAPluginFormat.h *********/ -#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ -#define __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ + /** Should return true if this parameter is a "meta" parameter. -#if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX + A meta-parameter is a parameter that changes other params. It is used + by some hosts (e.g. AudioUnit hosts). -// Sorry, this file is just a placeholder at the moment!... + By default this returns false. + */ + virtual bool isMetaParameter (int parameterIndex) const; -/** - Implements a plugin format manager for DirectX plugins. -*/ -class JUCE_API LADSPAPluginFormat : public AudioPluginFormat -{ -public: + /** Sends a signal to the host to tell it that the user is about to start changing this + parameter. - LADSPAPluginFormat(); - ~LADSPAPluginFormat(); + This allows the host to know when a parameter is actively being held by the user, and + it may use this information to help it record automation. - const String getName() const { return "LADSPA"; } - void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); - AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); - bool fileMightContainThisPluginType (const String& fileOrIdentifier); - const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } - const FileSearchPath getDefaultLocationsToSearch(); + If you call this, it must be matched by a later call to endParameterChangeGesture(). + */ + void beginParameterChangeGesture (int parameterIndex); - juce_UseDebuggingNewOperator + /** Tells the host that the user has finished changing this parameter. -private: - LADSPAPluginFormat (const LADSPAPluginFormat&); - const LADSPAPluginFormat& operator= (const LADSPAPluginFormat&); -}; + This allows the host to know when a parameter is actively being held by the user, and + it may use this information to help it record automation. -#endif + A call to this method must follow a call to beginParameterChangeGesture(). + */ + void endParameterChangeGesture (int parameterIndex); -#endif // __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_LADSPAPluginFormat.h *********/ + /** The filter can call this when something (apart from a parameter value) has changed. -#endif -#ifndef __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ + It sends a hint to the host that something like the program, number of parameters, + etc, has changed, and that it should update itself. + */ + void updateHostDisplay(); -/********* Start of inlined file: juce_VSTMidiEventList.h *********/ -#ifdef __aeffect__ + /** Returns the number of preset programs the filter supports. -#ifndef __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ -#define __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ + The value returned must be valid as soon as this object is created, and + must not change over its lifetime. -/** Holds a set of VSTMidiEvent objects and makes it easy to add - events to the list. + This value shouldn't be less than 1. + */ + virtual int getNumPrograms() = 0; - This is used by both the VST hosting code and the plugin wrapper. -*/ -class VSTMidiEventList -{ -public: + /** Returns the number of the currently active program. + */ + virtual int getCurrentProgram() = 0; - VSTMidiEventList() - : events (0), numEventsUsed (0), numEventsAllocated (0) - { - } + /** Called by the host to change the current program. + */ + virtual void setCurrentProgram (int index) = 0; - ~VSTMidiEventList() - { - freeEvents(); - } + /** Must return the name of a given program. */ + virtual const String getProgramName (int index) = 0; - void clear() - { - numEventsUsed = 0; + /** Called by the host to rename a program. + */ + virtual void changeProgramName (int index, const String& newName) = 0; - if (events != 0) - events->numEvents = 0; - } + /** The host will call this method when it wants to save the filter's internal state. - void addEvent (const void* const midiData, const int numBytes, const int frameOffset) - { - ensureSize (numEventsUsed + 1); + This must copy any info about the filter's state into the block of memory provided, + so that the host can store this and later restore it using setStateInformation(). - VstMidiEvent* const e = (VstMidiEvent*) (events->events [numEventsUsed]); - events->numEvents = ++numEventsUsed; + Note that there's also a getCurrentProgramStateInformation() method, which only + stores the current program, not the state of the entire filter. - if (numBytes <= 4) - { - if (e->type == kVstSysExType) - { - juce_free (((VstMidiSysexEvent*) e)->sysexDump); - e->type = kVstMidiType; - e->byteSize = sizeof (VstMidiEvent); - e->noteLength = 0; - e->noteOffset = 0; - e->detune = 0; - e->noteOffVelocity = 0; - } + See also the helper function copyXmlToBinary() for storing settings as XML. - e->deltaFrames = frameOffset; - memcpy (e->midiData, midiData, numBytes); - } - else - { - VstMidiSysexEvent* const se = (VstMidiSysexEvent*) e; + @see getCurrentProgramStateInformation + */ + virtual void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData) = 0; - if (se->type == kVstSysExType) - se->sysexDump = (char*) juce_realloc (se->sysexDump, numBytes); - else - se->sysexDump = (char*) juce_malloc (numBytes); + /** The host will call this method if it wants to save the state of just the filter's + current program. - memcpy (se->sysexDump, midiData, numBytes); + Unlike getStateInformation, this should only return the current program's state. - se->type = kVstSysExType; - se->byteSize = sizeof (VstMidiSysexEvent); - se->deltaFrames = frameOffset; - se->flags = 0; - se->dumpBytes = numBytes; - se->resvd1 = 0; - se->resvd2 = 0; - } - } + Not all hosts support this, and if you don't implement it, the base class + method just calls getStateInformation() instead. If you do implement it, be + sure to also implement getCurrentProgramStateInformation. - // Handy method to pull the events out of an event buffer supplied by the host - // or plugin. - static void addEventsToMidiBuffer (const VstEvents* events, MidiBuffer& dest) - { - for (int i = 0; i < events->numEvents; ++i) - { - const VstEvent* const e = events->events[i]; + @see getStateInformation, setCurrentProgramStateInformation + */ + virtual void getCurrentProgramStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); - if (e != 0) - { - if (e->type == kVstMidiType) - { - dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiEvent*) e)->midiData, - 4, e->deltaFrames); - } - else if (e->type == kVstSysExType) - { - dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiSysexEvent*) e)->sysexDump, - (int) ((const VstMidiSysexEvent*) e)->dumpBytes, - e->deltaFrames); - } - } - } - } + /** This must restore the filter's state from a block of data previously created + using getStateInformation(). - void ensureSize (int numEventsNeeded) - { - if (numEventsNeeded > numEventsAllocated) - { - numEventsNeeded = (numEventsNeeded + 32) & ~31; + Note that there's also a setCurrentProgramStateInformation() method, which tries + to restore just the current program, not the state of the entire filter. - const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; + See also the helper function getXmlFromBinary() for loading settings as XML. - if (events == 0) - events = (VstEvents*) juce_calloc (size); - else - events = (VstEvents*) juce_realloc (events, size); + @see setCurrentProgramStateInformation + */ + virtual void setStateInformation (const void* data, int sizeInBytes) = 0; - for (int i = numEventsAllocated; i < numEventsNeeded; ++i) - { - VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (jmax ((int) sizeof (VstMidiEvent), - (int) sizeof (VstMidiSysexEvent))); - e->type = kVstMidiType; - e->byteSize = sizeof (VstMidiEvent); + /** The host will call this method if it wants to restore the state of just the filter's + current program. - events->events[i] = (VstEvent*) e; - } + Not all hosts support this, and if you don't implement it, the base class + method just calls setStateInformation() instead. If you do implement it, be + sure to also implement getCurrentProgramStateInformation. - numEventsAllocated = numEventsNeeded; - } - } + @see setStateInformation, getCurrentProgramStateInformation + */ + virtual void setCurrentProgramStateInformation (const void* data, int sizeInBytes); - void freeEvents() - { - if (events != 0) - { - for (int i = numEventsAllocated; --i >= 0;) - { - VstMidiEvent* const e = (VstMidiEvent*) (events->events[i]); + /** Adds a listener that will be called when an aspect of this processor changes. */ + void addListener (AudioProcessorListener* const newListener) throw(); - if (e->type == kVstSysExType) - juce_free (((VstMidiSysexEvent*) e)->sysexDump); + /** Removes a previously added listener. */ + void removeListener (AudioProcessorListener* const listenerToRemove) throw(); - juce_free (e); - } + /** Not for public use - this is called before deleting an editor component. */ + void editorBeingDeleted (AudioProcessorEditor* const editor) throw(); - juce_free (events); - events = 0; - numEventsUsed = 0; - numEventsAllocated = 0; - } - } + /** Not for public use - this is called to initialise the processor. */ + void setPlayHead (AudioPlayHead* const newPlayHead) throw(); - VstEvents* events; + /** Not for public use - this is called to initialise the processor before playing. */ + void setPlayConfigDetails (const int numIns, const int numOuts, + const double sampleRate, + const int blockSize) throw(); -private: - int numEventsUsed, numEventsAllocated; -}; + juce_UseDebuggingNewOperator -#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ -#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ -/********* End of inlined file: juce_VSTMidiEventList.h *********/ +protected: -#endif -#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ + /** Helper function that just converts an xml element into a binary blob. -/********* Start of inlined file: juce_VSTPluginFormat.h *********/ -#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ -#define __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ + Use this in your filter's getStateInformation() method if you want to + store its state as xml. -#if JUCE_PLUGINHOST_VST + Then use getXmlFromBinary() to reverse this operation and retrieve the XML + from a binary blob. + */ + static void copyXmlToBinary (const XmlElement& xml, + JUCE_NAMESPACE::MemoryBlock& destData); -/** - Implements a plugin format manager for VSTs. -*/ -class JUCE_API VSTPluginFormat : public AudioPluginFormat -{ -public: + /** Retrieves an XML element that was stored as binary with the copyXmlToBinary() method. - VSTPluginFormat(); - ~VSTPluginFormat(); + This might return 0 if the data's unsuitable or corrupted. Otherwise it will return + an XmlElement object that the caller must delete when no longer needed. + */ + static XmlElement* getXmlFromBinary (const void* data, + const int sizeInBytes); - const String getName() const { return "VST"; } - void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); - AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); - bool fileMightContainThisPluginType (const String& fileOrIdentifier); - const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); - const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); - bool doesPluginStillExist (const PluginDescription& desc); - const FileSearchPath getDefaultLocationsToSearch(); + /** @internal */ + AudioPlayHead* playHead; - juce_UseDebuggingNewOperator + /** @internal */ + void sendParamChangeMessageToListeners (const int parameterIndex, const float newValue); private: - VSTPluginFormat (const VSTPluginFormat&); - const VSTPluginFormat& operator= (const VSTPluginFormat&); - - void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); -}; - -#endif -#endif // __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_VSTPluginFormat.h *********/ - -#endif -#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ + VoidArray listeners; + AudioProcessorEditor* activeEditor; + double sampleRate; + int blockSize, numInputChannels, numOutputChannels, latencySamples; + bool suspended, nonRealtime; + CriticalSection callbackLock, listenerLock; +#ifdef JUCE_DEBUG + BitArray changingParams; #endif -#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ -#endif -#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ + AudioProcessor (const AudioProcessor&); + const AudioProcessor& operator= (const AudioProcessor&); +}; -#endif -#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ +#endif // __JUCE_AUDIOPROCESSOR_JUCEHEADER__ +/********* End of inlined file: juce_AudioProcessor.h *********/ -#endif +/********* Start of inlined file: juce_PluginDescription.h *********/ #ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ +#define __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ -#endif -#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ +/** + A small class to represent some facts about a particular type of plugin. -/********* Start of inlined file: juce_PluginDirectoryScanner.h *********/ -#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ -#define __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ + This class is for storing and managing the details about a plugin without + actually having to load an instance of it. -/** - Scans a directory for plugins, and adds them to a KnownPluginList. + A KnownPluginList contains a list of PluginDescription objects. - To use one of these, create it and call scanNextFile() repeatedly, until - it returns false. + @see KnownPluginList */ -class JUCE_API PluginDirectoryScanner +class JUCE_API PluginDescription { public: - /** - Creates a scanner. + PluginDescription() throw(); + PluginDescription (const PluginDescription& other) throw(); + const PluginDescription& operator= (const PluginDescription& other) throw(); + ~PluginDescription() throw(); - @param listToAddResultsTo this will get the new types added to it. - @param formatToLookFor this is the type of format that you want to look for - @param directoriesToSearch the path to search - @param searchRecursively true to search recursively - @param deadMansPedalFile if this isn't File::nonexistent, then it will - be used as a file to store the names of any plugins - that crash during initialisation. If there are - any plugins listed in it, then these will always - be scanned after all other possible files have - been tried - in this way, even if there's a few - dodgy plugins in your path, then a couple of rescans - will still manage to find all the proper plugins. - It's probably best to choose a file in the user's - application data directory (alongside your app's - settings file) for this. The file format it uses - is just a list of filenames of the modules that - failed. - */ - PluginDirectoryScanner (KnownPluginList& listToAddResultsTo, - AudioPluginFormat& formatToLookFor, - FileSearchPath directoriesToSearch, - const bool searchRecursively, - const File& deadMansPedalFile); + /** The name of the plugin. */ + String name; - /** Destructor. */ - ~PluginDirectoryScanner(); + /** The plugin format, e.g. "VST", "AudioUnit", etc. + */ + String pluginFormatName; - /** Tries the next likely-looking file. + /** A category, such as "Dynamics", "Reverbs", etc. + */ + String category; - If dontRescanIfAlreadyInList is true, then the file will only be loaded and - re-tested if it's not already in the list, or if the file's modification - time has changed since the list was created. If dontRescanIfAlreadyInList is - false, the file will always be reloaded and tested. + /** The manufacturer. */ + String manufacturerName; - Returns false when there are no more files to try. - */ - bool scanNextFile (const bool dontRescanIfAlreadyInList); + /** The version. This string doesn't have any particular format. */ + String version; - /** Returns the description of the plugin that will be scanned during the next - call to scanNextFile(). + /** Either the file containing the plugin module, or some other unique way + of identifying it. - This is handy if you want to show the user which file is currently getting - scanned. + E.g. for an AU, this would be an ID string that the component manager + could use to retrieve the plugin. For a VST, it's the file path. */ - const String getNextPluginFileThatWillBeScanned() const throw(); + String fileOrIdentifier; - /** Returns the estimated progress, between 0 and 1. + /** The last time the plugin file was changed. + This is handy when scanning for new or changed plugins. */ - float getProgress() const { return progress; } + Time lastFileModTime; - /** This returns a list of all the filenames of things that looked like being - a plugin file, but which failed to open for some reason. + /** A unique ID for the plugin. + + Note that this might not be unique between formats, e.g. a VST and some + other format might actually have the same id. + + @see createIdentifierString */ - const StringArray& getFailedFiles() const throw() { return failedFiles; } + int uid; - juce_UseDebuggingNewOperator + /** True if the plugin identifies itself as a synthesiser. */ + bool isInstrument; -private: - KnownPluginList& list; - AudioPluginFormat& format; - StringArray filesOrIdentifiersToScan; - File deadMansPedalFile; - StringArray failedFiles; - int nextIndex; - float progress; + /** The number of inputs. */ + int numInputChannels; - const StringArray getDeadMansPedalFile() throw(); - void setDeadMansPedalFile (const StringArray& newContents) throw(); + /** The number of outputs. */ + int numOutputChannels; - PluginDirectoryScanner (const PluginDirectoryScanner&); - const PluginDirectoryScanner& operator= (const PluginDirectoryScanner&); -}; + /** Returns true if the two descriptions refer the the same plugin. -#endif // __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ -/********* End of inlined file: juce_PluginDirectoryScanner.h *********/ + This isn't quite as simple as them just having the same file (because of + shell plugins). + */ + bool isDuplicateOf (const PluginDescription& other) const; -#endif -#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ + /** Returns a string that can be saved and used to uniquely identify the + plugin again. -/********* Start of inlined file: juce_PluginListComponent.h *********/ -#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ -#define __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ + This contains less info than the XML encoding, and is independent of the + plugin's file location, so can be used to store a plugin ID for use + across different machines. + */ + const String createIdentifierString() const throw(); -/********* Start of inlined file: juce_ListBox.h *********/ -#ifndef __JUCE_LISTBOX_JUCEHEADER__ -#define __JUCE_LISTBOX_JUCEHEADER__ + /** Creates an XML object containing these details. -class ListViewport; + @see loadFromXml + */ + XmlElement* createXml() const; + + /** Reloads the info in this structure from an XML record that was previously + saved with createXML(). + + Returns true if the XML was a valid plugin description. + */ + bool loadFromXml (const XmlElement& xml); + + juce_UseDebuggingNewOperator +}; + +#endif // __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ +/********* End of inlined file: juce_PluginDescription.h *********/ /** - A subclass of this is used to drive a ListBox. + Base class for an active instance of a plugin. - @see ListBox + This derives from the AudioProcessor class, and adds some extra functionality + that helps when wrapping dynamically loaded plugins. + + @see AudioProcessor, AudioPluginFormat */ -class JUCE_API ListBoxModel +class JUCE_API AudioPluginInstance : public AudioProcessor { public: - /** Destructor. */ - virtual ~ListBoxModel() {} - - /** This has to return the number of items in the list. + /** Destructor. - @see ListBox::getNumRows() + Make sure that you delete any UI components that belong to this plugin before + deleting the plugin. */ - virtual int getNumRows() = 0; + virtual ~AudioPluginInstance(); - /** This method must be implemented to draw a row of the list. + /** Fills-in the appropriate parts of this plugin description object. */ - virtual void paintListBoxItem (int rowNumber, - Graphics& g, - int width, int height, - bool rowIsSelected) = 0; + virtual void fillInPluginDescription (PluginDescription& description) const = 0; - /** This is used to create or update a custom component to go in a row of the list. + juce_UseDebuggingNewOperator - Any row may contain a custom component, or can just be drawn with the paintListBoxItem() method - and handle mouse clicks with listBoxItemClicked(). +protected: + AudioPluginInstance(); - This method will be called whenever a custom component might need to be updated - e.g. - when the table is changed, or TableListBox::updateContent() is called. + AudioPluginInstance (const AudioPluginInstance&); + const AudioPluginInstance& operator= (const AudioPluginInstance&); +}; - If you don't need a custom component for the specified row, then return 0. +#endif // __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ +/********* End of inlined file: juce_AudioPluginInstance.h *********/ - If you do want a custom component, and the existingComponentToUpdate is null, then - this method must create a suitable new component and return it. +class PluginDescription; - If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created - by this method. In this case, the method must either update it to make sure it's correctly representing - the given row (which may be different from the one that the component was created for), or it can - delete this component and return a new one. +/** + The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc. - The component that your method returns will be deleted by the ListBox when it is no longer needed. - */ - virtual Component* refreshComponentForRow (int rowNumber, bool isRowSelected, - Component* existingComponentToUpdate); + Use the static getNumFormats() and getFormat() calls to find the types + of format that are available. +*/ +class JUCE_API AudioPluginFormat +{ +public: - /** This can be overridden to react to the user clicking on a row. + /** Destructor. */ + virtual ~AudioPluginFormat(); - @see listBoxItemDoubleClicked + /** Returns the format name. + + E.g. "VST", "AudioUnit", etc. */ - virtual void listBoxItemClicked (int row, const MouseEvent& e); + virtual const String getName() const = 0; - /** This can be overridden to react to the user double-clicking on a row. + /** This tries to create descriptions for all the plugin types available in + a binary module file. - @see listBoxItemClicked + The file will be some kind of DLL or bundle. + + Normally there will only be one type returned, but some plugins + (e.g. VST shells) can use a single DLL to create a set of different plugin + subtypes, so in that case, each subtype is returned as a separate object. */ - virtual void listBoxItemDoubleClicked (int row, const MouseEvent& e); + virtual void findAllTypesForFile (OwnedArray & results, + const String& fileOrIdentifier) = 0; - /** This can be overridden to react to the user double-clicking on a part of the list where - there are no rows. + /** Tries to recreate a type from a previously generated PluginDescription. - @see listBoxItemClicked + @see PluginDescription::createInstance */ - virtual void backgroundClicked(); - - /** Override this to be informed when rows are selected or deselected. + virtual AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc) = 0; - This will be called whenever a row is selected or deselected. If a range of - rows is selected all at once, this will just be called once for that event. + /** Should do a quick check to see if this file or directory might be a plugin of + this format. - @param lastRowSelected the last row that the user selected. If no - rows are currently selected, this may be -1. + This is for searching for potential files, so it shouldn't actually try to + load the plugin or do anything time-consuming. */ - virtual void selectedRowsChanged (int lastRowSelected); + virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; - /** Override this to be informed when the delete key is pressed. + /** Returns a readable version of the name of the plugin that this identifier refers to. + */ + virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; - If no rows are selected when they press the key, this won't be called. + /** Checks whether this plugin could possibly be loaded. - @param lastRowSelected the last row that had been selected when they pressed the - key - if there are multiple selections, this might not be - very useful + It doesn't actually need to load it, just to check whether the file or component + still exists. */ - virtual void deleteKeyPressed (int lastRowSelected); - - /** Override this to be informed when the return key is pressed. + virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; - If no rows are selected when they press the key, this won't be called. + /** Searches a suggested set of directories for any plugins in this format. - @param lastRowSelected the last row that had been selected when they pressed the - key - if there are multiple selections, this might not be - very useful + The path might be ignored, e.g. by AUs, which are found by the OS rather + than manually. */ - virtual void returnKeyPressed (int lastRowSelected); + virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, + const bool recursive) = 0; - /** Override this to be informed when the list is scrolled. + /** Returns the typical places to look for this kind of plugin. - This might be caused by the user moving the scrollbar, or by programmatic changes - to the list position. + Note that if this returns no paths, it means that the format can't be scanned-for + (i.e. it's an internal format that doesn't live in files) */ - virtual void listWasScrolled(); - - /** To allow rows from your list to be dragged-and-dropped, implement this method. + virtual const FileSearchPath getDefaultLocationsToSearch() = 0; - If this returns a non-empty name then when the user drags a row, the listbox will - try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger - a drag-and-drop operation, using this string as the source description, with the listbox - itself as the source component. + juce_UseDebuggingNewOperator - @see DragAndDropContainer::startDragging - */ - virtual const String getDragSourceDescription (const SparseSet& currentlySelectedRows); +protected: + AudioPluginFormat() throw(); - /** You can override this to provide tool tips for specific rows. - @see TooltipClient - */ - virtual const String getTooltipForRow (int row); + AudioPluginFormat (const AudioPluginFormat&); + const AudioPluginFormat& operator= (const AudioPluginFormat&); }; -/** - A list of items that can be scrolled vertically. +#endif // __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_AudioPluginFormat.h *********/ - To create a list, you'll need to create a subclass of ListBoxModel. This can - either paint each row of the list and respond to events via callbacks, or for - more specialised tasks, it can supply a custom component to fill each row. +#if JUCE_PLUGINHOST_AU && JUCE_MAC - @see ComboBox, TableListBox +/** + Implements a plugin format manager for AudioUnits. */ -class JUCE_API ListBox : public Component, - public SettableTooltipClient +class JUCE_API AudioUnitPluginFormat : public AudioPluginFormat { public: - /** Creates a ListBox. + AudioUnitPluginFormat(); + ~AudioUnitPluginFormat(); - The model pointer passed-in can be null, in which case you can set it later - with setModel(). - */ - ListBox (const String& componentName, - ListBoxModel* const model); + const String getName() const { return "AudioUnit"; } + void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); + AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); + bool fileMightContainThisPluginType (const String& fileOrIdentifier); + const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); + const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); + bool doesPluginStillExist (const PluginDescription& desc); + const FileSearchPath getDefaultLocationsToSearch(); - /** Destructor. */ - ~ListBox(); + juce_UseDebuggingNewOperator - /** Changes the current data model to display. */ - void setModel (ListBoxModel* const newModel); +private: + AudioUnitPluginFormat (const AudioUnitPluginFormat&); + const AudioUnitPluginFormat& operator= (const AudioUnitPluginFormat&); +}; - /** Returns the current list model. */ - ListBoxModel* getModel() const throw() { return model; } +#endif - /** Causes the list to refresh its content. +#endif // __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_AudioUnitPluginFormat.h *********/ - Call this when the number of rows in the list changes, or if you want it - to call refreshComponentForRow() on all the row components. +#endif +#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ - Be careful not to call it from a different thread, though, as it's not - thread-safe. - */ - void updateContent(); +/********* Start of inlined file: juce_DirectXPluginFormat.h *********/ +#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ +#define __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ - /** Turns on multiple-selection of rows. +#if JUCE_PLUGINHOST_DX && JUCE_WIN32 - By default this is disabled. +// Sorry, this file is just a placeholder at the moment!... - When your row component gets clicked you'll need to call the - selectRowsBasedOnModifierKeys() method to tell the list that it's been - clicked and to get it to do the appropriate selection based on whether - the ctrl/shift keys are held down. - */ - void setMultipleSelectionEnabled (bool shouldBeEnabled); +/** + Implements a plugin format manager for DirectX plugins. +*/ +class JUCE_API DirectXPluginFormat : public AudioPluginFormat +{ +public: - /** Makes the list react to mouse moves by selecting the row that the mouse if over. + DirectXPluginFormat(); + ~DirectXPluginFormat(); - This function is here primarily for the ComboBox class to use, but might be - useful for some other purpose too. - */ - void setMouseMoveSelectsRows (bool shouldSelect); + const String getName() const { return "DirectX"; } + void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); + AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); + bool fileMightContainThisPluginType (const String& fileOrIdentifier); + const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } + const FileSearchPath getDefaultLocationsToSearch(); - /** Selects a row. + juce_UseDebuggingNewOperator - If the row is already selected, this won't do anything. +private: + DirectXPluginFormat (const DirectXPluginFormat&); + const DirectXPluginFormat& operator= (const DirectXPluginFormat&); +}; - @param rowNumber the row to select - @param dontScrollToShowThisRow if true, the list's position won't change; if false and - the selected row is off-screen, it'll scroll to make - sure that row is on-screen - @param deselectOthersFirst if true and there are multiple selections, these will - first be deselected before this item is selected - @see isRowSelected, selectRowsBasedOnModifierKeys, flipRowSelection, deselectRow, - deselectAllRows, selectRangeOfRows - */ - void selectRow (const int rowNumber, - bool dontScrollToShowThisRow = false, - bool deselectOthersFirst = true); +#endif - /** Selects a set of rows. +#endif // __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_DirectXPluginFormat.h *********/ - This will add these rows to the current selection, so you might need to - clear the current selection first with deselectAllRows() +#endif +#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ - @param firstRow the first row to select (inclusive) - @param lastRow the last row to select (inclusive) - */ - void selectRangeOfRows (int firstRow, - int lastRow); +/********* Start of inlined file: juce_LADSPAPluginFormat.h *********/ +#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ +#define __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ - /** Deselects a row. +#if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX - If it's not currently selected, this will do nothing. +// Sorry, this file is just a placeholder at the moment!... - @see selectRow, deselectAllRows - */ - void deselectRow (const int rowNumber); +/** + Implements a plugin format manager for DirectX plugins. +*/ +class JUCE_API LADSPAPluginFormat : public AudioPluginFormat +{ +public: - /** Deselects any currently selected rows. + LADSPAPluginFormat(); + ~LADSPAPluginFormat(); - @see deselectRow - */ - void deselectAllRows(); + const String getName() const { return "LADSPA"; } + void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); + AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); + bool fileMightContainThisPluginType (const String& fileOrIdentifier); + const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } + const FileSearchPath getDefaultLocationsToSearch(); - /** Selects or deselects a row. + juce_UseDebuggingNewOperator - If the row's currently selected, this deselects it, and vice-versa. - */ - void flipRowSelection (const int rowNumber); +private: + LADSPAPluginFormat (const LADSPAPluginFormat&); + const LADSPAPluginFormat& operator= (const LADSPAPluginFormat&); +}; - /** Returns a sparse set indicating the rows that are currently selected. +#endif - @see setSelectedRows - */ - const SparseSet getSelectedRows() const; +#endif // __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_LADSPAPluginFormat.h *********/ - /** Sets the rows that should be selected, based on an explicit set of ranges. +#endif +#ifndef __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ - If sendNotificationEventToModel is true, the ListBoxModel::selectedRowsChanged() - method will be called. If it's false, no notification will be sent to the model. +/********* Start of inlined file: juce_VSTMidiEventList.h *********/ +#ifdef __aeffect__ - @see getSelectedRows - */ - void setSelectedRows (const SparseSet& setOfRowsToBeSelected, - const bool sendNotificationEventToModel = true); +#ifndef __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ +#define __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ - /** Checks whether a row is selected. - */ - bool isRowSelected (const int rowNumber) const; +/** Holds a set of VSTMidiEvent objects and makes it easy to add + events to the list. - /** Returns the number of rows that are currently selected. + This is used by both the VST hosting code and the plugin wrapper. +*/ +class VSTMidiEventList +{ +public: - @see getSelectedRow, isRowSelected, getLastRowSelected - */ - int getNumSelectedRows() const; + VSTMidiEventList() + : numEventsUsed (0), numEventsAllocated (0) + { + } - /** Returns the row number of a selected row. + ~VSTMidiEventList() + { + freeEvents(); + } - This will return the row number of the Nth selected row. The row numbers returned will - be sorted in order from low to high. + void clear() + { + numEventsUsed = 0; - @param index the index of the selected row to return, (from 0 to getNumSelectedRows() - 1) - @returns the row number, or -1 if the index was out of range or if there aren't any rows - selected - @see getNumSelectedRows, isRowSelected, getLastRowSelected - */ - int getSelectedRow (const int index = 0) const; + if (events != 0) + events->numEvents = 0; + } - /** Returns the last row that the user selected. + void addEvent (const void* const midiData, const int numBytes, const int frameOffset) + { + ensureSize (numEventsUsed + 1); - This isn't the same as the highest row number that is currently selected - if the user - had multiply-selected rows 10, 5 and then 6 in that order, this would return 6. + VstMidiEvent* const e = (VstMidiEvent*) (events->events [numEventsUsed]); + events->numEvents = ++numEventsUsed; - If nothing is selected, it will return -1. - */ - int getLastRowSelected() const; + if (numBytes <= 4) + { + if (e->type == kVstSysExType) + { + juce_free (((VstMidiSysexEvent*) e)->sysexDump); + e->type = kVstMidiType; + e->byteSize = sizeof (VstMidiEvent); + e->noteLength = 0; + e->noteOffset = 0; + e->detune = 0; + e->noteOffVelocity = 0; + } - /** Multiply-selects rows based on the modifier keys. + e->deltaFrames = frameOffset; + memcpy (e->midiData, midiData, numBytes); + } + else + { + VstMidiSysexEvent* const se = (VstMidiSysexEvent*) e; - If no modifier keys are down, this will select the given row and - deselect any others. + if (se->type == kVstSysExType) + se->sysexDump = (char*) juce_realloc (se->sysexDump, numBytes); + else + se->sysexDump = (char*) juce_malloc (numBytes); - If the ctrl (or command on the Mac) key is down, it'll flip the - state of the selected row. + memcpy (se->sysexDump, midiData, numBytes); - If the shift key is down, it'll select up to the given row from the - last row selected. + se->type = kVstSysExType; + se->byteSize = sizeof (VstMidiSysexEvent); + se->deltaFrames = frameOffset; + se->flags = 0; + se->dumpBytes = numBytes; + se->resvd1 = 0; + se->resvd2 = 0; + } + } - @see selectRow - */ - void selectRowsBasedOnModifierKeys (const int rowThatWasClickedOn, - const ModifierKeys& modifiers); + // Handy method to pull the events out of an event buffer supplied by the host + // or plugin. + static void addEventsToMidiBuffer (const VstEvents* events, MidiBuffer& dest) + { + for (int i = 0; i < events->numEvents; ++i) + { + const VstEvent* const e = events->events[i]; - /** Scrolls the list to a particular position. + if (e != 0) + { + if (e->type == kVstMidiType) + { + dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiEvent*) e)->midiData, + 4, e->deltaFrames); + } + else if (e->type == kVstSysExType) + { + dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiSysexEvent*) e)->sysexDump, + (int) ((const VstMidiSysexEvent*) e)->dumpBytes, + e->deltaFrames); + } + } + } + } - The proportion is between 0 and 1.0, so 0 scrolls to the top of the list, - 1.0 scrolls to the bottom. + void ensureSize (int numEventsNeeded) + { + if (numEventsNeeded > numEventsAllocated) + { + numEventsNeeded = (numEventsNeeded + 32) & ~31; - If the total number of rows all fit onto the screen at once, then this - method won't do anything. + const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; - @see getVerticalPosition - */ - void setVerticalPosition (const double newProportion); + if (events == 0) + events.calloc (size, 1); + else + events.realloc (size, 1); - /** Returns the current vertical position as a proportion of the total. + for (int i = numEventsAllocated; i < numEventsNeeded; ++i) + { + VstMidiEvent* const e = (VstMidiEvent*) juce_calloc (jmax ((int) sizeof (VstMidiEvent), + (int) sizeof (VstMidiSysexEvent))); + e->type = kVstMidiType; + e->byteSize = sizeof (VstMidiEvent); - This can be used in conjunction with setVerticalPosition() to save and restore - the list's position. It returns a value in the range 0 to 1. + events->events[i] = (VstEvent*) e; + } - @see setVerticalPosition - */ - double getVerticalPosition() const; + numEventsAllocated = numEventsNeeded; + } + } - /** Scrolls if necessary to make sure that a particular row is visible. - */ - void scrollToEnsureRowIsOnscreen (const int row); + void freeEvents() + { + if (events != 0) + { + for (int i = numEventsAllocated; --i >= 0;) + { + VstMidiEvent* const e = (VstMidiEvent*) (events->events[i]); - /** Returns a pointer to the scrollbar. + if (e->type == kVstSysExType) + juce_free (((VstMidiSysexEvent*) e)->sysexDump); - (Unlikely to be useful for most people). - */ - ScrollBar* getVerticalScrollBar() const throw(); + juce_free (e); + } - /** Returns a pointer to the scrollbar. + events.free(); + numEventsUsed = 0; + numEventsAllocated = 0; + } + } - (Unlikely to be useful for most people). - */ - ScrollBar* getHorizontalScrollBar() const throw(); + HeapBlock events; - /** Finds the row index that contains a given x,y position. +private: + int numEventsUsed, numEventsAllocated; +}; - The position is relative to the ListBox's top-left. +#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ +#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__ +/********* End of inlined file: juce_VSTMidiEventList.h *********/ - If no row exists at this position, the method will return -1. +#endif +#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ - @see getComponentForRowNumber - */ - int getRowContainingPosition (const int x, const int y) const throw(); +/********* Start of inlined file: juce_VSTPluginFormat.h *********/ +#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ +#define __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ - /** Finds a row index that would be the most suitable place to insert a new - item for a given position. +#if JUCE_PLUGINHOST_VST - This is useful when the user is e.g. dragging and dropping onto the listbox, - because it lets you easily choose the best position to insert the item that - they drop, based on where they drop it. +/** + Implements a plugin format manager for VSTs. +*/ +class JUCE_API VSTPluginFormat : public AudioPluginFormat +{ +public: - If the position is out of range, this will return -1. If the position is - beyond the end of the list, it will return getNumRows() to indicate the end - of the list. + VSTPluginFormat(); + ~VSTPluginFormat(); - @see getComponentForRowNumber - */ - int getInsertionIndexForPosition (const int x, const int y) const throw(); + const String getName() const { return "VST"; } + void findAllTypesForFile (OwnedArray & results, const String& fileOrIdentifier); + AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); + bool fileMightContainThisPluginType (const String& fileOrIdentifier); + const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); + const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); + bool doesPluginStillExist (const PluginDescription& desc); + const FileSearchPath getDefaultLocationsToSearch(); - /** Returns the position of one of the rows, relative to the top-left of - the listbox. + juce_UseDebuggingNewOperator - This may be off-screen, and the range of the row number that is passed-in is - not checked to see if it's a valid row. - */ - const Rectangle getRowPosition (const int rowNumber, - const bool relativeToComponentTopLeft) const throw(); +private: + VSTPluginFormat (const VSTPluginFormat&); + const VSTPluginFormat& operator= (const VSTPluginFormat&); - /** Finds the row component for a given row in the list. + void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); +}; - The component returned will have been created using createRowComponent(). +#endif +#endif // __JUCE_VSTPLUGINFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_VSTPluginFormat.h *********/ - If the component for this row is off-screen or if the row is out-of-range, - this will return 0. +#endif +#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__ - @see getRowContainingPosition - */ - Component* getComponentForRowNumber (const int rowNumber) const throw(); +#endif +#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ - /** Returns the row number that the given component represents. +/********* Start of inlined file: juce_AudioPluginFormatManager.h *********/ +#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ +#define __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ - If the component isn't one of the list's rows, this will return -1. - */ - int getRowNumberOfComponent (Component* const rowComponent) const throw(); +/** + This maintains a list of known AudioPluginFormats. - /** Returns the width of a row (which may be less than the width of this component - if there's a scrollbar). - */ - int getVisibleRowWidth() const throw(); + @see AudioPluginFormat +*/ +class JUCE_API AudioPluginFormatManager : public DeletedAtShutdown +{ +public: - /** Sets the height of each row in the list. + AudioPluginFormatManager() throw(); - The default height is 22 pixels. + /** Destructor. */ + ~AudioPluginFormatManager() throw(); - @see getRowHeight + juce_DeclareSingleton_SingleThreaded (AudioPluginFormatManager, false); + + /** Adds any formats that it knows about, e.g. VST. */ - void setRowHeight (const int newHeight); + void addDefaultFormats(); - /** Returns the height of a row in the list. + /** Returns the number of types of format that are available. - @see setRowHeight + Use getFormat() to get one of them. */ - int getRowHeight() const throw() { return rowHeight; } + int getNumFormats() throw(); - /** Returns the number of rows actually visible. + /** Returns one of the available formats. - This is the number of whole rows which will fit on-screen, so the value might - be more than the actual number of rows in the list. + @see getNumFormats */ - int getNumRowsOnScreen() const throw(); - - /** A set of colour IDs to use to change the colour of various aspects of the label. + AudioPluginFormat* getFormat (const int index) throw(); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** Adds a format to the list. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + The object passed in will be owned and deleted by the manager. */ - enum ColourIds - { - backgroundColourId = 0x1002800, /**< The background colour to fill the list with. - Make this transparent if you don't want the background to be filled. */ - outlineColourId = 0x1002810, /**< An optional colour to use to draw a border around the list. - Make this transparent to not have an outline. */ - textColourId = 0x1002820 /**< The preferred colour to use for drawing text in the listbox. */ - }; + void addFormat (AudioPluginFormat* const format) throw(); - /** Sets the thickness of a border that will be drawn around the box. + /** Tries to load the type for this description, by trying all the formats + that this manager knows about. - To set the colour of the outline, use @code setColour (ListBox::outlineColourId, colourXYZ); @endcode - @see outlineColourId + The caller is responsible for deleting the object that is returned. + + If it can't load the plugin, it returns 0 and leaves a message in the + errorMessage string. */ - void setOutlineThickness (const int outlineThickness); + AudioPluginInstance* createPluginInstance (const PluginDescription& description, + String& errorMessage) const; - /** Returns the thickness of outline that will be drawn around the listbox. + /** Checks that the file or component for this plugin actually still exists. - @see setOutlineColour + (This won't try to load the plugin) */ - int getOutlineThickness() const throw() { return outlineThickness; } + bool doesPluginStillExist (const PluginDescription& description) const; - /** Sets a component that the list should use as a header. + juce_UseDebuggingNewOperator - This will position the given component at the top of the list, maintaining the - height of the component passed-in, but rescaling it horizontally to match the - width of the items in the listbox. +private: + OwnedArray formats; - The component will be deleted when setHeaderComponent() is called with a - different component, or when the listbox is deleted. - */ - void setHeaderComponent (Component* const newHeaderComponent); + AudioPluginFormatManager (const AudioPluginFormatManager&); + const AudioPluginFormatManager& operator= (const AudioPluginFormatManager&); +}; - /** Changes the width of the rows in the list. +#endif // __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_AudioPluginFormatManager.h *********/ - This can be used to make the list's row components wider than the list itself - the - width of the rows will be either the width of the list or this value, whichever is - greater, and if the rows become wider than the list, a horizontal scrollbar will - appear. +#endif +#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__ - The default value for this is 0, which means that the rows will always - be the same width as the list. - */ - void setMinimumContentWidth (const int newMinimumWidth); +#endif +#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ - /** Returns the space currently available for the row items, taking into account - borders, scrollbars, etc. - */ - int getVisibleContentWidth() const throw(); +/********* Start of inlined file: juce_KnownPluginList.h *********/ +#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ +#define __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ - /** Repaints one of the rows. +/** + Manages a list of plugin types. - This is a lightweight alternative to calling updateContent, and just causes a - repaint of the row's area. + This can be easily edited, saved and loaded, and used to create instances of + the plugin types in it. + + @see PluginListComponent +*/ +class JUCE_API KnownPluginList : public ChangeBroadcaster +{ +public: + + /** Creates an empty list. */ - void repaintRow (const int rowNumber) throw(); + KnownPluginList(); - /** This fairly obscure method creates an image that just shows the currently - selected row components. + /** Destructor. */ + ~KnownPluginList(); - It's a handy method for doing drag-and-drop, as it can be passed to the - DragAndDropContainer for use as the drag image. + /** Clears the list. */ + void clear(); - Note that it will make the row components temporarily invisible, so if you're - using custom components this could affect them if they're sensitive to that - sort of thing. + /** Returns the number of types currently in the list. + @see getType + */ + int getNumTypes() const throw() { return types.size(); } - @see Component::createComponentSnapshot + /** Returns one of the types. + @see getNumTypes */ - Image* createSnapshotOfSelectedRows (int& x, int& y); + PluginDescription* getType (const int index) const throw() { return types [index]; } - /** Returns the viewport that this ListBox uses. + /** Looks for a type in the list which comes from this file. + */ + PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); - You may need to use this to change parameters such as whether scrollbars - are shown, etc. - */ - Viewport* getViewport() const throw(); + /** Looks for a type in the list which matches a plugin type ID. - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - bool keyStateChanged (const bool isKeyDown); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void paintOverChildren (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void visibilityChanged(); - /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - /** @internal */ - void mouseMove (const MouseEvent&); - /** @internal */ - void mouseExit (const MouseEvent&); - /** @internal */ - void mouseUp (const MouseEvent&); - /** @internal */ - void colourChanged(); - /** @internal */ - void startDragAndDrop (const MouseEvent& e, const String& dragDescription); + The identifierString parameter must have been created by + PluginDescription::createIdentifierString(). + */ + PluginDescription* getTypeForIdentifierString (const String& identifierString) const throw(); - juce_UseDebuggingNewOperator + /** Adds a type manually from its description. */ + bool addType (const PluginDescription& type); -private: + /** Removes a type. */ + void removeType (const int index) throw(); - friend class ListViewport; - friend class TableListBox; - ListBoxModel* model; - ListViewport* viewport; - Component* headerComponent; - int totalItems, rowHeight, minimumRowWidth; - int outlineThickness; - int lastMouseX, lastMouseY, lastRowSelected; - bool mouseMoveSelects, multipleSelection, hasDoneInitialUpdate; - SparseSet selected; + /** Looks for all types that can be loaded from a given file, and adds them + to the list. - void selectRowInternal (const int rowNumber, - bool dontScrollToShowThisRow, - bool deselectOthersFirst, - bool isMouseClick); + If dontRescanIfAlreadyInList is true, then the file will only be loaded and + re-tested if it's not already in the list, or if the file's modification + time has changed since the list was created. If dontRescanIfAlreadyInList is + false, the file will always be reloaded and tested. - ListBox (const ListBox&); - const ListBox& operator= (const ListBox&); -}; + Returns true if any new types were added, and all the types found in this + file (even if it was already known and hasn't been re-scanned) get returned + in the array. + */ + bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, + const bool dontRescanIfAlreadyInList, + OwnedArray & typesFound, + AudioPluginFormat& formatToUse); -#endif // __JUCE_LISTBOX_JUCEHEADER__ -/********* End of inlined file: juce_ListBox.h *********/ + /** Returns true if the specified file is already known about and if it + hasn't been modified since our entry was created. + */ + bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); -/********* Start of inlined file: juce_TextButton.h *********/ -#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ -#define __JUCE_TEXTBUTTON_JUCEHEADER__ + /** Scans and adds a bunch of files that might have been dragged-and-dropped. -/** - A button that uses the standard lozenge-shaped background with a line of - text on it. + If any types are found in the files, their descriptions are returned in the array. + */ + void scanAndAddDragAndDroppedFiles (const StringArray& filenames, + OwnedArray & typesFound); - @see Button, DrawableButton -*/ -class JUCE_API TextButton : public Button -{ -public: + /** Sort methods used to change the order of the plugins in the list. + */ + enum SortMethod + { + defaultOrder = 0, + sortAlphabetically, + sortByCategory, + sortByManufacturer, + sortByFileSystemLocation + }; - /** Creates a TextButton. + /** Adds all the plugin types to a popup menu so that the user can select one. - @param buttonName the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) - @param toolTip an optional string to use as a toolip + Depending on the sort method, it may add sub-menus for categories, + manufacturers, etc. - @see Button + Use getIndexChosenByMenu() to find out the type that was chosen. */ - TextButton (const String& buttonName, - const String& toolTip = String::empty); - - /** Destructor. */ - ~TextButton(); + void addToMenu (PopupMenu& menu, + const SortMethod sortMethod) const; - /** A set of colour IDs to use to change the colour of various aspects of the button. + /** Converts a menu item index that has been chosen into its index in this list. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + Returns -1 if it's not an ID that was used. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + @see addToMenu */ - enum ColourIds - { - buttonColourId = 0x1000100, /**< The colour used to fill the button shape (when the button is toggled - 'off'). The look-and-feel class might re-interpret this to add - effects, etc. */ - buttonOnColourId = 0x1000101, /**< The colour used to fill the button shape (when the button is toggled - 'on'). The look-and-feel class might re-interpret this to add - effects, etc. */ - textColourOffId = 0x1000102, /**< The colour to use for the button's text when the button's toggle state is "off". */ - textColourOnId = 0x1000103 /**< The colour to use for the button's text.when the button's toggle state is "on". */ - }; + int getIndexChosenByMenu (const int menuResultCode) const; - /** Resizes the button to fit neatly around its current text. + /** Sorts the list. */ + void sort (const SortMethod method); - If newHeight is >= 0, the button's height will be changed to this - value. If it's less than zero, its height will be unaffected. + /** Creates some XML that can be used to store the state of this list. */ - void changeWidthToFitText (const int newHeight = -1); - - /** This can be overridden to use different fonts than the default one. + XmlElement* createXml() const; - Note that you'll need to set the font's size appropriately, too. + /** Recreates the state of this list from its stored XML format. */ - virtual const Font getFont(); + void recreateFromXml (const XmlElement& xml); juce_UseDebuggingNewOperator -protected: - /** @internal */ - void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown); - /** @internal */ - void colourChanged(); - private: - TextButton (const TextButton&); - const TextButton& operator= (const TextButton&); + OwnedArray types; + + KnownPluginList (const KnownPluginList&); + const KnownPluginList& operator= (const KnownPluginList&); }; -#endif // __JUCE_TEXTBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_TextButton.h *********/ +#endif // __JUCE_KNOWNPLUGINLIST_JUCEHEADER__ +/********* End of inlined file: juce_KnownPluginList.h *********/ + +#endif +#ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__ + +#endif +#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ + +/********* Start of inlined file: juce_PluginDirectoryScanner.h *********/ +#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ +#define __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ /** - A component displaying a list of plugins, with options to scan for them, - add, remove and sort them. + Scans a directory for plugins, and adds them to a KnownPluginList. + + To use one of these, create it and call scanNextFile() repeatedly, until + it returns false. */ -class JUCE_API PluginListComponent : public Component, - public ListBoxModel, - public ChangeListener, - public ButtonListener, - public Timer +class JUCE_API PluginDirectoryScanner { public: /** - Creates the list component. - - For info about the deadMansPedalFile, see the PluginDirectoryScanner constructor. + Creates a scanner. - The properties file, if supplied, is used to store the user's last search paths. + @param listToAddResultsTo this will get the new types added to it. + @param formatToLookFor this is the type of format that you want to look for + @param directoriesToSearch the path to search + @param searchRecursively true to search recursively + @param deadMansPedalFile if this isn't File::nonexistent, then it will + be used as a file to store the names of any plugins + that crash during initialisation. If there are + any plugins listed in it, then these will always + be scanned after all other possible files have + been tried - in this way, even if there's a few + dodgy plugins in your path, then a couple of rescans + will still manage to find all the proper plugins. + It's probably best to choose a file in the user's + application data directory (alongside your app's + settings file) for this. The file format it uses + is just a list of filenames of the modules that + failed. */ - PluginListComponent (KnownPluginList& listToRepresent, - const File& deadMansPedalFile, - PropertiesFile* const propertiesToUse); + PluginDirectoryScanner (KnownPluginList& listToAddResultsTo, + AudioPluginFormat& formatToLookFor, + FileSearchPath directoriesToSearch, + const bool searchRecursively, + const File& deadMansPedalFile); /** Destructor. */ - ~PluginListComponent(); + ~PluginDirectoryScanner(); - /** @internal */ - void resized(); - /** @internal */ - bool isInterestedInFileDrag (const StringArray& files); - /** @internal */ - void filesDropped (const StringArray& files, int, int); - /** @internal */ - int getNumRows(); - /** @internal */ - void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected); - /** @internal */ - void deleteKeyPressed (int lastRowSelected); - /** @internal */ - void buttonClicked (Button* b); - /** @internal */ - void changeListenerCallback (void*); - /** @internal */ - void timerCallback(); + /** Tries the next likely-looking file. + + If dontRescanIfAlreadyInList is true, then the file will only be loaded and + re-tested if it's not already in the list, or if the file's modification + time has changed since the list was created. If dontRescanIfAlreadyInList is + false, the file will always be reloaded and tested. + + Returns false when there are no more files to try. + */ + bool scanNextFile (const bool dontRescanIfAlreadyInList); + + /** Returns the description of the plugin that will be scanned during the next + call to scanNextFile(). + + This is handy if you want to show the user which file is currently getting + scanned. + */ + const String getNextPluginFileThatWillBeScanned() const throw(); + + /** Returns the estimated progress, between 0 and 1. + */ + float getProgress() const { return progress; } + + /** This returns a list of all the filenames of things that looked like being + a plugin file, but which failed to open for some reason. + */ + const StringArray& getFailedFiles() const throw() { return failedFiles; } juce_UseDebuggingNewOperator private: KnownPluginList& list; + AudioPluginFormat& format; + StringArray filesOrIdentifiersToScan; File deadMansPedalFile; - ListBox* listBox; - TextButton* optionsButton; - PropertiesFile* propertiesToUse; - int typeToScan; + StringArray failedFiles; + int nextIndex; + float progress; - void scanFor (AudioPluginFormat* format); + const StringArray getDeadMansPedalFile() throw(); + void setDeadMansPedalFile (const StringArray& newContents) throw(); - PluginListComponent (const PluginListComponent&); - const PluginListComponent& operator= (const PluginListComponent&); + PluginDirectoryScanner (const PluginDirectoryScanner&); + const PluginDirectoryScanner& operator= (const PluginDirectoryScanner&); }; -#endif // __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_PluginListComponent.h *********/ +#endif // __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__ +/********* End of inlined file: juce_PluginDirectoryScanner.h *********/ #endif -#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ +#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_AiffAudioFormat.h *********/ -#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ -#define __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ +/********* Start of inlined file: juce_PluginListComponent.h *********/ +#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ +#define __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_AudioFormat.h *********/ -#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ -#define __JUCE_AUDIOFORMAT_JUCEHEADER__ +/********* Start of inlined file: juce_ListBox.h *********/ +#ifndef __JUCE_LISTBOX_JUCEHEADER__ +#define __JUCE_LISTBOX_JUCEHEADER__ -/********* Start of inlined file: juce_AudioFormatWriter.h *********/ -#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ -#define __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ +class ListViewport; /** - Writes samples to an audio file stream. - - A subclass that writes a specific type of audio format will be created by - an AudioFormat object. - - After creating one of these with the AudioFormat::createWriterFor() method - you can call its write() method to store the samples, and then delete it. + A subclass of this is used to drive a ListBox. - @see AudioFormat, AudioFormatReader + @see ListBox */ -class JUCE_API AudioFormatWriter +class JUCE_API ListBoxModel { -protected: +public: - /** Creates an AudioFormatWriter object. + /** Destructor. */ + virtual ~ListBoxModel() {} - @param destStream the stream to write to - this will be deleted - by this object when it is no longer needed - @param formatName the description that will be returned by the getFormatName() - method - @param sampleRate the sample rate to use - the base class just stores - this value, it doesn't do anything with it - @param numberOfChannels the number of channels to write - the base class just stores - this value, it doesn't do anything with it - @param bitsPerSample the bit depth of the stream - the base class just stores - this value, it doesn't do anything with it + /** This has to return the number of items in the list. + + @see ListBox::getNumRows() */ - AudioFormatWriter (OutputStream* const destStream, - const String& formatName, - const double sampleRate, - const unsigned int numberOfChannels, - const unsigned int bitsPerSample); + virtual int getNumRows() = 0; -public: - /** Destructor. */ - virtual ~AudioFormatWriter(); + /** This method must be implemented to draw a row of the list. + */ + virtual void paintListBoxItem (int rowNumber, + Graphics& g, + int width, int height, + bool rowIsSelected) = 0; - /** Returns a description of what type of format this is. + /** This is used to create or update a custom component to go in a row of the list. - E.g. "AIFF file" - */ - const String getFormatName() const throw() { return formatName; } + Any row may contain a custom component, or can just be drawn with the paintListBoxItem() method + and handle mouse clicks with listBoxItemClicked(). - /** Writes a set of samples to the audio stream. + This method will be called whenever a custom component might need to be updated - e.g. + when the table is changed, or TableListBox::updateContent() is called. - Note that if you're trying to write the contents of an AudioSampleBuffer, you - can use AudioSampleBuffer::writeToAudioWriter(). + If you don't need a custom component for the specified row, then return 0. - @param samplesToWrite an array of arrays containing the sample data for - each channel to write. This is a zero-terminated - array of arrays, and can contain a different number - of channels than the actual stream uses, and the - writer should do its best to cope with this. - If the format is fixed-point, each channel will be formatted - as an array of signed integers using the full 32-bit - range -0x80000000 to 0x7fffffff, regardless of the source's - bit-depth. If it is a floating-point format, you should treat - the arrays as arrays of floats, and just cast it to an (int**) - to pass it into the method. - @param numSamples the number of samples to write + If you do want a custom component, and the existingComponentToUpdate is null, then + this method must create a suitable new component and return it. + + If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created + by this method. In this case, the method must either update it to make sure it's correctly representing + the given row (which may be different from the one that the component was created for), or it can + delete this component and return a new one. + + The component that your method returns will be deleted by the ListBox when it is no longer needed. */ - virtual bool write (const int** samplesToWrite, - int numSamples) = 0; + virtual Component* refreshComponentForRow (int rowNumber, bool isRowSelected, + Component* existingComponentToUpdate); - /** Reads a section of samples from an AudioFormatReader, and writes these to - the output. + /** This can be overridden to react to the user clicking on a row. - This will take care of any floating-point conversion that's required to convert - between the two formats. It won't deal with sample-rate conversion, though. + @see listBoxItemDoubleClicked + */ + virtual void listBoxItemClicked (int row, const MouseEvent& e); - If numSamplesToRead < 0, it will write the entire length of the reader. + /** This can be overridden to react to the user double-clicking on a row. - @returns false if it can't read or write properly during the operation + @see listBoxItemClicked */ - bool writeFromAudioReader (AudioFormatReader& reader, - int64 startSample, - int64 numSamplesToRead); + virtual void listBoxItemDoubleClicked (int row, const MouseEvent& e); - /** Reads some samples from an AudioSource, and writes these to the output. + /** This can be overridden to react to the user double-clicking on a part of the list where + there are no rows. - The source must already have been initialised with the AudioSource::prepareToPlay() method + @see listBoxItemClicked + */ + virtual void backgroundClicked(); - @param source the source to read from - @param numSamplesToRead total number of samples to read and write - @param samplesPerBlock the maximum number of samples to fetch from the source - @returns false if it can't read or write properly during the operation + /** Override this to be informed when rows are selected or deselected. + + This will be called whenever a row is selected or deselected. If a range of + rows is selected all at once, this will just be called once for that event. + + @param lastRowSelected the last row that the user selected. If no + rows are currently selected, this may be -1. */ - bool writeFromAudioSource (AudioSource& source, - int numSamplesToRead, - const int samplesPerBlock = 2048); + virtual void selectedRowsChanged (int lastRowSelected); - /** Returns the sample rate being used. */ - double getSampleRate() const throw() { return sampleRate; } + /** Override this to be informed when the delete key is pressed. - /** Returns the number of channels being written. */ - int getNumChannels() const throw() { return numChannels; } + If no rows are selected when they press the key, this won't be called. - /** Returns the bit-depth of the data being written. */ - int getBitsPerSample() const throw() { return bitsPerSample; } + @param lastRowSelected the last row that had been selected when they pressed the + key - if there are multiple selections, this might not be + very useful + */ + virtual void deleteKeyPressed (int lastRowSelected); - /** Returns true if it's a floating-point format, false if it's fixed-point. */ - bool isFloatingPoint() const throw() { return usesFloatingPointData; } + /** Override this to be informed when the return key is pressed. - juce_UseDebuggingNewOperator + If no rows are selected when they press the key, this won't be called. -protected: - /** The sample rate of the stream. */ - double sampleRate; + @param lastRowSelected the last row that had been selected when they pressed the + key - if there are multiple selections, this might not be + very useful + */ + virtual void returnKeyPressed (int lastRowSelected); - /** The number of channels being written to the stream. */ - unsigned int numChannels; + /** Override this to be informed when the list is scrolled. - /** The bit depth of the file. */ - unsigned int bitsPerSample; + This might be caused by the user moving the scrollbar, or by programmatic changes + to the list position. + */ + virtual void listWasScrolled(); - /** True if it's a floating-point format, false if it's fixed-point. */ - bool usesFloatingPointData; + /** To allow rows from your list to be dragged-and-dropped, implement this method. - /** The output stream for Use by subclasses. */ - OutputStream* output; + If this returns a non-empty name then when the user drags a row, the listbox will + try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger + a drag-and-drop operation, using this string as the source description, with the listbox + itself as the source component. -private: - String formatName; -}; + @see DragAndDropContainer::startDragging + */ + virtual const String getDragSourceDescription (const SparseSet& currentlySelectedRows); -#endif // __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ -/********* End of inlined file: juce_AudioFormatWriter.h *********/ + /** You can override this to provide tool tips for specific rows. + @see TooltipClient + */ + virtual const String getTooltipForRow (int row); +}; /** - Subclasses of AudioFormat are used to read and write different audio - file formats. + A list of items that can be scrolled vertically. - @see AudioFormatReader, AudioFormatWriter, WavAudioFormat, AiffAudioFormat + To create a list, you'll need to create a subclass of ListBoxModel. This can + either paint each row of the list and respond to events via callbacks, or for + more specialised tasks, it can supply a custom component to fill each row. + + @see ComboBox, TableListBox */ -class JUCE_API AudioFormat +class JUCE_API ListBox : public Component, + public SettableTooltipClient { public: - /** Destructor. */ - virtual ~AudioFormat(); - - /** Returns the name of this format. + /** Creates a ListBox. - e.g. "WAV file" or "AIFF file" + The model pointer passed-in can be null, in which case you can set it later + with setModel(). */ - const String& getFormatName() const; + ListBox (const String& componentName, + ListBoxModel* const model); - /** Returns all the file extensions that might apply to a file of this format. + /** Destructor. */ + ~ListBox(); - The first item will be the one that's preferred when creating a new file. + /** Changes the current data model to display. */ + void setModel (ListBoxModel* const newModel); - So for a wav file this might just return ".wav"; for an AIFF file it might - return two items, ".aif" and ".aiff" - */ - const StringArray& getFileExtensions() const; + /** Returns the current list model. */ + ListBoxModel* getModel() const throw() { return model; } - /** Returns true if this the given file can be read by this format. + /** Causes the list to refresh its content. - Subclasses shouldn't do too much work here, just check the extension or - file type. The base class implementation just checks the file's extension - against one of the ones that was registered in the constructor. + Call this when the number of rows in the list changes, or if you want it + to call refreshComponentForRow() on all the row components. + + Be careful not to call it from a different thread, though, as it's not + thread-safe. */ - virtual bool canHandleFile (const File& fileToTest); + void updateContent(); - /** Returns a set of sample rates that the format can read and write. */ - virtual const Array getPossibleSampleRates() = 0; + /** Turns on multiple-selection of rows. - /** Returns a set of bit depths that the format can read and write. */ - virtual const Array getPossibleBitDepths() = 0; + By default this is disabled. - /** Returns true if the format can do 2-channel audio. */ - virtual bool canDoStereo() = 0; + When your row component gets clicked you'll need to call the + selectRowsBasedOnModifierKeys() method to tell the list that it's been + clicked and to get it to do the appropriate selection based on whether + the ctrl/shift keys are held down. + */ + void setMultipleSelectionEnabled (bool shouldBeEnabled); - /** Returns true if the format can do 1-channel audio. */ - virtual bool canDoMono() = 0; + /** Makes the list react to mouse moves by selecting the row that the mouse if over. - /** Returns true if the format uses compressed data. */ - virtual bool isCompressed(); + This function is here primarily for the ComboBox class to use, but might be + useful for some other purpose too. + */ + void setMouseMoveSelectsRows (bool shouldSelect); - /** Returns a list of different qualities that can be used when writing. + /** Selects a row. - Non-compressed formats will just return an empty array, but for something - like Ogg-Vorbis or MP3, it might return a list of bit-rates, etc. + If the row is already selected, this won't do anything. - When calling createWriterFor(), an index from this array is passed in to - tell the format which option is required. + @param rowNumber the row to select + @param dontScrollToShowThisRow if true, the list's position won't change; if false and + the selected row is off-screen, it'll scroll to make + sure that row is on-screen + @param deselectOthersFirst if true and there are multiple selections, these will + first be deselected before this item is selected + @see isRowSelected, selectRowsBasedOnModifierKeys, flipRowSelection, deselectRow, + deselectAllRows, selectRangeOfRows */ - virtual const StringArray getQualityOptions(); + void selectRow (const int rowNumber, + bool dontScrollToShowThisRow = false, + bool deselectOthersFirst = true); - /** Tries to create an object that can read from a stream containing audio - data in this format. + /** Selects a set of rows. - The reader object that is returned can be used to read from the stream, and - should then be deleted by the caller. + This will add these rows to the current selection, so you might need to + clear the current selection first with deselectAllRows() - @param sourceStream the stream to read from - the AudioFormatReader object - that is returned will delete this stream when it no longer - needs it. - @param deleteStreamIfOpeningFails if no reader can be created, this determines whether this method - should delete the stream object that was passed-in. (If a valid - reader is returned, it will always be in charge of deleting the - stream, so this parameter is ignored) - @see AudioFormatReader + @param firstRow the first row to select (inclusive) + @param lastRow the last row to select (inclusive) */ - virtual AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails) = 0; - - /** Tries to create an object that can write to a stream with this audio format. + void selectRangeOfRows (int firstRow, + int lastRow); - The writer object that is returned can be used to write to the stream, and - should then be deleted by the caller. + /** Deselects a row. - If the stream can't be created for some reason (e.g. the parameters passed in - here aren't suitable), this will return 0. + If it's not currently selected, this will do nothing. - @param streamToWriteTo the stream that the data will go to - this will be - deleted by the AudioFormatWriter object when it's no longer - needed. If no AudioFormatWriter can be created by this method, - the stream will NOT be deleted, so that the caller can re-use it - to try to open a different format, etc - @param sampleRateToUse the sample rate for the file, which must be one of the ones - returned by getPossibleSampleRates() - @param numberOfChannels the number of channels - this must be either 1 or 2, and - the choice will depend on the results of canDoMono() and - canDoStereo() - @param bitsPerSample the bits per sample to use - this must be one of the values - returned by getPossibleBitDepths() - @param metadataValues a set of metadata values that the writer should try to write - to the stream. Exactly what these are depends on the format, - and the subclass doesn't actually have to do anything with - them if it doesn't want to. Have a look at the specific format - implementation classes to see possible values that can be - used - @param qualityOptionIndex the index of one of compression qualities returned by the - getQualityOptions() method. If there aren't any quality options - for this format, just pass 0 in this parameter, as it'll be - ignored - @see AudioFormatWriter + @see selectRow, deselectAllRows */ - virtual AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex) = 0; + void deselectRow (const int rowNumber); -protected: - /** Creates an AudioFormat object. + /** Deselects any currently selected rows. - @param formatName this sets the value that will be returned by getFormatName() - @param fileExtensions a zero-terminated list of file extensions - this is what will - be returned by getFileExtension() + @see deselectRow */ - AudioFormat (const String& formatName, - const tchar** const fileExtensions); + void deselectAllRows(); -private: + /** Selects or deselects a row. - String formatName; - StringArray fileExtensions; -}; + If the row's currently selected, this deselects it, and vice-versa. + */ + void flipRowSelection (const int rowNumber); -#endif // __JUCE_AUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_AudioFormat.h *********/ + /** Returns a sparse set indicating the rows that are currently selected. -/** - Reads and Writes AIFF format audio files. + @see setSelectedRows + */ + const SparseSet getSelectedRows() const; - @see AudioFormat -*/ -class JUCE_API AiffAudioFormat : public AudioFormat -{ -public: + /** Sets the rows that should be selected, based on an explicit set of ranges. - /** Creates an format object. */ - AiffAudioFormat(); + If sendNotificationEventToModel is true, the ListBoxModel::selectedRowsChanged() + method will be called. If it's false, no notification will be sent to the model. - /** Destructor. */ - ~AiffAudioFormat(); + @see getSelectedRows + */ + void setSelectedRows (const SparseSet& setOfRowsToBeSelected, + const bool sendNotificationEventToModel = true); - const Array getPossibleSampleRates(); - const Array getPossibleBitDepths(); - bool canDoStereo(); - bool canDoMono(); -#if JUCE_MAC - bool canHandleFile (const File& fileToTest); -#endif + /** Checks whether a row is selected. + */ + bool isRowSelected (const int rowNumber) const; - AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails); + /** Returns the number of rows that are currently selected. - AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex); + @see getSelectedRow, isRowSelected, getLastRowSelected + */ + int getNumSelectedRows() const; - juce_UseDebuggingNewOperator -}; + /** Returns the row number of a selected row. -#endif // __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_AiffAudioFormat.h *********/ + This will return the row number of the Nth selected row. The row numbers returned will + be sorted in order from low to high. -#endif -#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ + @param index the index of the selected row to return, (from 0 to getNumSelectedRows() - 1) + @returns the row number, or -1 if the index was out of range or if there aren't any rows + selected + @see getNumSelectedRows, isRowSelected, getLastRowSelected + */ + int getSelectedRow (const int index = 0) const; -#endif -#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ + /** Returns the last row that the user selected. -/********* Start of inlined file: juce_AudioFormatManager.h *********/ -#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ -#define __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ + This isn't the same as the highest row number that is currently selected - if the user + had multiply-selected rows 10, 5 and then 6 in that order, this would return 6. -/** - A class for keeping a list of available audio formats, and for deciding which - one to use to open a given file. + If nothing is selected, it will return -1. + */ + int getLastRowSelected() const; - You can either use this class as a singleton object, or create instances of it - yourself. Once created, use its registerFormat() method to tell it which - formats it should use. + /** Multiply-selects rows based on the modifier keys. - @see AudioFormat -*/ -class JUCE_API AudioFormatManager -{ -public: + If no modifier keys are down, this will select the given row and + deselect any others. - /** Creates an empty format manager. + If the ctrl (or command on the Mac) key is down, it'll flip the + state of the selected row. - Before it'll be any use, you'll need to call registerFormat() with all the - formats you want it to be able to recognise. - */ - AudioFormatManager(); + If the shift key is down, it'll select up to the given row from the + last row selected. - /** Destructor. */ - ~AudioFormatManager(); + @see selectRow + */ + void selectRowsBasedOnModifierKeys (const int rowThatWasClickedOn, + const ModifierKeys& modifiers); - juce_DeclareSingleton (AudioFormatManager, false); + /** Scrolls the list to a particular position. - /** Adds a format to the manager's list of available file types. + The proportion is between 0 and 1.0, so 0 scrolls to the top of the list, + 1.0 scrolls to the bottom. - The object passed-in will be deleted by this object, so don't keep a pointer - to it! + If the total number of rows all fit onto the screen at once, then this + method won't do anything. - If makeThisTheDefaultFormat is true, then the getDefaultFormat() method will - return this one when called. + @see getVerticalPosition */ - void registerFormat (AudioFormat* newFormat, - const bool makeThisTheDefaultFormat); + void setVerticalPosition (const double newProportion); - /** Handy method to make it easy to register the formats that come with Juce. + /** Returns the current vertical position as a proportion of the total. - Currently, this will add WAV and AIFF to the list. + This can be used in conjunction with setVerticalPosition() to save and restore + the list's position. It returns a value in the range 0 to 1. + + @see setVerticalPosition */ - void registerBasicFormats(); + double getVerticalPosition() const; - /** Clears the list of known formats. */ - void clearFormats(); + /** Scrolls if necessary to make sure that a particular row is visible. + */ + void scrollToEnsureRowIsOnscreen (const int row); - /** Returns the number of currently registered file formats. */ - int getNumKnownFormats() const; + /** Returns a pointer to the scrollbar. - /** Returns one of the registered file formats. */ - AudioFormat* getKnownFormat (const int index) const; + (Unlikely to be useful for most people). + */ + ScrollBar* getVerticalScrollBar() const throw(); - /** Looks for which of the known formats is listed as being for a given file - extension. + /** Returns a pointer to the scrollbar. - The extension may have a dot before it, so e.g. ".wav" or "wav" are both ok. + (Unlikely to be useful for most people). */ - AudioFormat* findFormatForFileExtension (const String& fileExtension) const; + ScrollBar* getHorizontalScrollBar() const throw(); - /** Returns the format which has been set as the default one. + /** Finds the row index that contains a given x,y position. - You can set a format as being the default when it is registered. It's useful - when you want to write to a file, because the best format may change between - platforms, e.g. AIFF is preferred on the Mac, WAV on Windows. + The position is relative to the ListBox's top-left. - If none has been set as the default, this method will just return the first - one in the list. + If no row exists at this position, the method will return -1. + + @see getComponentForRowNumber */ - AudioFormat* getDefaultFormat() const; + int getRowContainingPosition (const int x, const int y) const throw(); - /** Returns a set of wildcards for file-matching that contains the extensions for - all known formats. + /** Finds a row index that would be the most suitable place to insert a new + item for a given position. - E.g. if might return "*.wav;*.aiff" if it just knows about wavs and aiffs. + This is useful when the user is e.g. dragging and dropping onto the listbox, + because it lets you easily choose the best position to insert the item that + they drop, based on where they drop it. + + If the position is out of range, this will return -1. If the position is + beyond the end of the list, it will return getNumRows() to indicate the end + of the list. + + @see getComponentForRowNumber */ - const String getWildcardForAllFormats() const; + int getInsertionIndexForPosition (const int x, const int y) const throw(); - /** Searches through the known formats to try to create a suitable reader for - this file. + /** Returns the position of one of the rows, relative to the top-left of + the listbox. - If none of the registered formats can open the file, it'll return 0. If it - returns a reader, it's the caller's responsibility to delete the reader. + This may be off-screen, and the range of the row number that is passed-in is + not checked to see if it's a valid row. */ - AudioFormatReader* createReaderFor (const File& audioFile); + const Rectangle getRowPosition (const int rowNumber, + const bool relativeToComponentTopLeft) const throw(); - /** Searches through the known formats to try to create a suitable reader for - this stream. + /** Finds the row component for a given row in the list. - The stream object that is passed-in will be deleted by this method or by the - reader that is returned, so the caller should not keep any references to it. + The component returned will have been created using createRowComponent(). - The stream that is passed-in must be capable of being repositioned so - that all the formats can have a go at opening it. + If the component for this row is off-screen or if the row is out-of-range, + this will return 0. - If none of the registered formats can open the stream, it'll return 0. If it - returns a reader, it's the caller's responsibility to delete the reader. + @see getRowContainingPosition */ - AudioFormatReader* createReaderFor (InputStream* audioFileStream); + Component* getComponentForRowNumber (const int rowNumber) const throw(); - juce_UseDebuggingNewOperator + /** Returns the row number that the given component represents. -private: - VoidArray knownFormats; - int defaultFormatIndex; -}; + If the component isn't one of the list's rows, this will return -1. + */ + int getRowNumberOfComponent (Component* const rowComponent) const throw(); -#endif // __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_AudioFormatManager.h *********/ + /** Returns the width of a row (which may be less than the width of this component + if there's a scrollbar). + */ + int getVisibleRowWidth() const throw(); -#endif -#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ + /** Sets the height of each row in the list. -#endif -#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ + The default height is 22 pixels. -#endif -#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ + @see getRowHeight + */ + void setRowHeight (const int newHeight); -/********* Start of inlined file: juce_AudioSubsectionReader.h *********/ -#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ -#define __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ + /** Returns the height of a row in the list. -/** - This class is used to wrap an AudioFormatReader and only read from a - subsection of the file. + @see setRowHeight + */ + int getRowHeight() const throw() { return rowHeight; } - So if you have a reader which can read a 1000 sample file, you could wrap it - in one of these to only access, e.g. samples 100 to 200, and any samples - outside that will come back as 0. Accessing sample 0 from this reader will - actually read the first sample from the other's subsection, which might - be at a non-zero position. + /** Returns the number of rows actually visible. - @see AudioFormatReader -*/ -class JUCE_API AudioSubsectionReader : public AudioFormatReader -{ -public: + This is the number of whole rows which will fit on-screen, so the value might + be more than the actual number of rows in the list. + */ + int getNumRowsOnScreen() const throw(); - /** Creates a AudioSubsectionReader for a given data source. + /** A set of colour IDs to use to change the colour of various aspects of the label. - @param sourceReader the source reader from which we'll be taking data - @param subsectionStartSample the sample within the source reader which will be - mapped onto sample 0 for this reader. - @param subsectionLength the number of samples from the source that will - make up the subsection. If this reader is asked for - any samples beyond this region, it will return zero. - @param deleteSourceWhenDeleted if true, the sourceReader object will be deleted when - this object is deleted. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - AudioSubsectionReader (AudioFormatReader* const sourceReader, - const int64 subsectionStartSample, - const int64 subsectionLength, - const bool deleteSourceWhenDeleted); + enum ColourIds + { + backgroundColourId = 0x1002800, /**< The background colour to fill the list with. + Make this transparent if you don't want the background to be filled. */ + outlineColourId = 0x1002810, /**< An optional colour to use to draw a border around the list. + Make this transparent to not have an outline. */ + textColourId = 0x1002820 /**< The preferred colour to use for drawing text in the listbox. */ + }; - /** Destructor. */ - ~AudioSubsectionReader(); + /** Sets the thickness of a border that will be drawn around the box. - bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, - int64 startSampleInFile, int numSamples); + To set the colour of the outline, use @code setColour (ListBox::outlineColourId, colourXYZ); @endcode + @see outlineColourId + */ + void setOutlineThickness (const int outlineThickness); - void readMaxLevels (int64 startSample, - int64 numSamples, - float& lowestLeft, - float& highestLeft, - float& lowestRight, - float& highestRight); + /** Returns the thickness of outline that will be drawn around the listbox. - juce_UseDebuggingNewOperator + @see setOutlineColour + */ + int getOutlineThickness() const throw() { return outlineThickness; } -private: - AudioFormatReader* const source; - int64 startSample, length; - const bool deleteSourceWhenDeleted; + /** Sets a component that the list should use as a header. - AudioSubsectionReader (const AudioSubsectionReader&); - const AudioSubsectionReader& operator= (const AudioSubsectionReader&); -}; + This will position the given component at the top of the list, maintaining the + height of the component passed-in, but rescaling it horizontally to match the + width of the items in the listbox. -#endif // __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ -/********* End of inlined file: juce_AudioSubsectionReader.h *********/ + The component will be deleted when setHeaderComponent() is called with a + different component, or when the listbox is deleted. + */ + void setHeaderComponent (Component* const newHeaderComponent); -#endif -#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ + /** Changes the width of the rows in the list. -/********* Start of inlined file: juce_AudioThumbnail.h *********/ -#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ -#define __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ + This can be used to make the list's row components wider than the list itself - the + width of the rows will be either the width of the list or this value, whichever is + greater, and if the rows become wider than the list, a horizontal scrollbar will + appear. -class AudioThumbnailCache; + The default value for this is 0, which means that the rows will always + be the same width as the list. + */ + void setMinimumContentWidth (const int newMinimumWidth); -/** - Makes it easy to quickly draw scaled views of the waveform shape of an - audio file. + /** Returns the space currently available for the row items, taking into account + borders, scrollbars, etc. + */ + int getVisibleContentWidth() const throw(); - To use this class, just create an AudioThumbNail class for the file you want - to draw, call setSource to tell it which file or resource to use, then call - drawChannel() to draw it. + /** Repaints one of the rows. - The class will asynchronously scan the wavefile to create its scaled-down view, - so you should make your UI repaint itself as this data comes in. To do this, the - AudioThumbnail is a ChangeBroadcaster, and will broadcast a message when its - listeners should repaint themselves. + This is a lightweight alternative to calling updateContent, and just causes a + repaint of the row's area. + */ + void repaintRow (const int rowNumber) throw(); - The thumbnail stores an internal low-res version of the wave data, and this can - be loaded and saved to avoid having to scan the file again. + /** This fairly obscure method creates an image that just shows the currently + selected row components. - @see AudioThumbnailCache -*/ -class JUCE_API AudioThumbnail : public ChangeBroadcaster, - public TimeSliceClient, - private Timer -{ -public: + It's a handy method for doing drag-and-drop, as it can be passed to the + DragAndDropContainer for use as the drag image. - /** Creates an audio thumbnail. + Note that it will make the row components temporarily invisible, so if you're + using custom components this could affect them if they're sensitive to that + sort of thing. - @param sourceSamplesPerThumbnailSample when creating a stored, low-res version - of the audio data, this is the scale at which it should be done. (This - number is the number of original samples that will be averaged for each - low-res sample) - @param formatManagerToUse the audio format manager that is used to open the file - @param cacheToUse an instance of an AudioThumbnailCache - this provides a background - thread and storage that is used to by the thumbnail, and the cache - object can be shared between multiple thumbnails + @see Component::createComponentSnapshot */ - AudioThumbnail (const int sourceSamplesPerThumbnailSample, - AudioFormatManager& formatManagerToUse, - AudioThumbnailCache& cacheToUse); + Image* createSnapshotOfSelectedRows (int& x, int& y); - /** Destructor. */ - ~AudioThumbnail(); + /** Returns the viewport that this ListBox uses. - /** Specifies the file or stream that contains the audio file. + You may need to use this to change parameters such as whether scrollbars + are shown, etc. + */ + Viewport* getViewport() const throw(); - For a file, just call - @code - setSource (new FileInputSource (file)) - @endcode + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + bool keyStateChanged (const bool isKeyDown); + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void paintOverChildren (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void visibilityChanged(); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + void mouseMove (const MouseEvent&); + /** @internal */ + void mouseExit (const MouseEvent&); + /** @internal */ + void mouseUp (const MouseEvent&); + /** @internal */ + void colourChanged(); + /** @internal */ + void startDragAndDrop (const MouseEvent& e, const String& dragDescription); - You can pass a zero in here to clear the thumbnail. + juce_UseDebuggingNewOperator - The source that is passed in will be deleted by this object when it is no - longer needed - */ - void setSource (InputSource* const newSource); +private: - /** Reloads the low res thumbnail data from an input stream. + friend class ListViewport; + friend class TableListBox; + ListBoxModel* model; + ListViewport* viewport; + Component* headerComponent; + int totalItems, rowHeight, minimumRowWidth; + int outlineThickness; + int lastMouseX, lastMouseY, lastRowSelected; + bool mouseMoveSelects, multipleSelection, hasDoneInitialUpdate; + SparseSet selected; - The thumb will automatically attempt to reload itself from its - AudioThumbnailCache. - */ - void loadFrom (InputStream& input); + void selectRowInternal (const int rowNumber, + bool dontScrollToShowThisRow, + bool deselectOthersFirst, + bool isMouseClick); - /** Saves the low res thumbnail data to an output stream. + ListBox (const ListBox&); + const ListBox& operator= (const ListBox&); +}; - The thumb will automatically attempt to save itself to its - AudioThumbnailCache after it finishes scanning the wave file. - */ - void saveTo (OutputStream& output) const; +#endif // __JUCE_LISTBOX_JUCEHEADER__ +/********* End of inlined file: juce_ListBox.h *********/ - /** Returns the number of channels in the file. - */ - int getNumChannels() const throw(); +/********* Start of inlined file: juce_TextButton.h *********/ +#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ +#define __JUCE_TEXTBUTTON_JUCEHEADER__ - /** Returns the length of the audio file, in seconds. +/** + A button that uses the standard lozenge-shaped background with a line of + text on it. + + @see Button, DrawableButton +*/ +class JUCE_API TextButton : public Button +{ +public: + + /** Creates a TextButton. + + @param buttonName the text to put in the button (the component's name is also + initially set to this string, but these can be changed later + using the setName() and setButtonText() methods) + @param toolTip an optional string to use as a toolip + + @see Button */ - double getTotalLength() const throw(); + TextButton (const String& buttonName, + const String& toolTip = String::empty); - /** Renders the waveform shape for a channel. + /** Destructor. */ + ~TextButton(); - The waveform will be drawn within the specified rectangle, where startTime - and endTime specify the times within the audio file that should be positioned - at the left and right edges of the rectangle. + /** A set of colour IDs to use to change the colour of various aspects of the button. - The waveform will be scaled vertically so that a full-volume sample will fill - the rectangle vertically, but you can also specify an extra vertical scale factor - with the verticalZoomFactor parameter. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void drawChannel (Graphics& g, - int x, int y, int w, int h, - double startTimeSeconds, - double endTimeSeconds, - int channelNum, - const float verticalZoomFactor); + enum ColourIds + { + buttonColourId = 0x1000100, /**< The colour used to fill the button shape (when the button is toggled + 'off'). The look-and-feel class might re-interpret this to add + effects, etc. */ + buttonOnColourId = 0x1000101, /**< The colour used to fill the button shape (when the button is toggled + 'on'). The look-and-feel class might re-interpret this to add + effects, etc. */ + textColourOffId = 0x1000102, /**< The colour to use for the button's text when the button's toggle state is "off". */ + textColourOnId = 0x1000103 /**< The colour to use for the button's text.when the button's toggle state is "on". */ + }; - /** Returns true if the low res preview is fully generated. + /** Resizes the button to fit neatly around its current text. + + If newHeight is >= 0, the button's height will be changed to this + value. If it's less than zero, its height will be unaffected. */ - bool isFullyLoaded() const throw(); + void changeWidthToFitText (const int newHeight = -1); - /** @internal */ - bool useTimeSlice(); - /** @internal */ - void timerCallback(); + /** This can be overridden to use different fonts than the default one. + + Note that you'll need to set the font's size appropriately, too. + */ + virtual const Font getFont(); juce_UseDebuggingNewOperator +protected: + /** @internal */ + void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown); + /** @internal */ + void colourChanged(); + private: - AudioFormatManager& formatManagerToUse; - AudioThumbnailCache& cache; - InputSource* source; + TextButton (const TextButton&); + const TextButton& operator= (const TextButton&); +}; - CriticalSection readerLock; - AudioFormatReader* reader; +#endif // __JUCE_TEXTBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_TextButton.h *********/ - MemoryBlock data, cachedLevels; - int orginalSamplesPerThumbnailSample; +/** + A component displaying a list of plugins, with options to scan for them, + add, remove and sort them. +*/ +class JUCE_API PluginListComponent : public Component, + public ListBoxModel, + public ChangeListener, + public ButtonListener, + public Timer +{ +public: - int numChannelsCached, numSamplesCached; - double cachedStart, cachedTimePerPixel; - bool cacheNeedsRefilling; + /** + Creates the list component. - void clear(); + For info about the deadMansPedalFile, see the PluginDirectoryScanner constructor. - AudioFormatReader* createReader() const; + The properties file, if supplied, is used to store the user's last search paths. + */ + PluginListComponent (KnownPluginList& listToRepresent, + const File& deadMansPedalFile, + PropertiesFile* const propertiesToUse); - void generateSection (AudioFormatReader& reader, - int64 startSample, - int numSamples); + /** Destructor. */ + ~PluginListComponent(); - char* getChannelData (int channel) const; + /** @internal */ + void resized(); + /** @internal */ + bool isInterestedInFileDrag (const StringArray& files); + /** @internal */ + void filesDropped (const StringArray& files, int, int); + /** @internal */ + int getNumRows(); + /** @internal */ + void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected); + /** @internal */ + void deleteKeyPressed (int lastRowSelected); + /** @internal */ + void buttonClicked (Button* b); + /** @internal */ + void changeListenerCallback (void*); + /** @internal */ + void timerCallback(); - void refillCache (const int numSamples, - double startTime, - const double timePerPixel); + juce_UseDebuggingNewOperator - friend class AudioThumbnailCache; +private: + KnownPluginList& list; + File deadMansPedalFile; + ListBox* listBox; + TextButton* optionsButton; + PropertiesFile* propertiesToUse; + int typeToScan; - // true if it needs more callbacks from the readNextBlockFromAudioFile() method - bool initialiseFromAudioFile (AudioFormatReader& reader); + void scanFor (AudioPluginFormat* format); - // returns true if more needs to be read - bool readNextBlockFromAudioFile (AudioFormatReader& reader); + PluginListComponent (const PluginListComponent&); + const PluginListComponent& operator= (const PluginListComponent&); }; -#endif // __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ -/********* End of inlined file: juce_AudioThumbnail.h *********/ +#endif // __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_PluginListComponent.h *********/ #endif -#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ +#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ -/********* Start of inlined file: juce_AudioThumbnailCache.h *********/ -#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ -#define __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ +#endif +#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ -struct ThumbnailCacheEntry; +#endif +#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ + +#endif +#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ + +/********* Start of inlined file: juce_AudioProcessorGraph.h *********/ +#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ /** - An instance of this class is used to manage multiple AudioThumbnail objects. + A type of AudioProcessor which plays back a graph of other AudioProcessors. - The cache runs a single background thread that is shared by all the thumbnails - that need it, and it maintains a set of low-res previews in memory, to avoid - having to re-scan audio files too often. + Use one of these objects if you want to wire-up a set of AudioProcessors + and play back the result. - @see AudioThumbnail + Processors can be added to the graph as "nodes" using addNode(), and once + added, you can connect any of their input or output channels to other + nodes using addConnection(). + + To play back a graph through an audio device, you might want to use an + AudioProcessorPlayer object. */ -class JUCE_API AudioThumbnailCache : public TimeSliceThread +class JUCE_API AudioProcessorGraph : public AudioProcessor, + public AsyncUpdater { public: - /** Creates a cache object. - - The maxNumThumbsToStore parameter lets you specify how many previews should - be kept in memory at once. + /** Creates an empty graph. */ - AudioThumbnailCache (const int maxNumThumbsToStore); + AudioProcessorGraph(); - /** Destructor. */ - ~AudioThumbnailCache(); + /** Destructor. - /** Clears out any stored thumbnails. + Any processor objects that have been added to the graph will also be deleted. */ - void clear(); + ~AudioProcessorGraph(); - /** Reloads the specified thumb if this cache contains the appropriate stored - data. + /** Represents one of the nodes, or processors, in an AudioProcessorGraph. - This is called automatically by the AudioThumbnail class, so you shouldn't - normally need to call it directly. + To create a node, call AudioProcessorGraph::addNode(). */ - bool loadThumb (AudioThumbnail& thumb, const int64 hashCode); + class JUCE_API Node : public ReferenceCountedObject + { + public: + /** Destructor. + */ + ~Node(); - /** Stores the cachable data from the specified thumb in this cache. + /** The ID number assigned to this node. - This is called automatically by the AudioThumbnail class, so you shouldn't - normally need to call it directly. - */ - void storeThumb (const AudioThumbnail& thumb, const int64 hashCode); + This is assigned by the graph that owns it, and can't be changed. + */ + const uint32 id; - juce_UseDebuggingNewOperator + /** The actual processor object that this node represents. + */ + AudioProcessor* const processor; -private: + /** A set of user-definable properties that are associated with this node. - OwnedArray thumbs; - int maxNumThumbsToStore; + This can be used to attach values to the node for whatever purpose seems + useful. For example, you might store an x and y position if your application + is displaying the nodes on-screen. + */ + PropertySet properties; - friend class AudioThumbnail; - void addThumbnail (AudioThumbnail* const thumb); - void removeThumbnail (AudioThumbnail* const thumb); -}; + /** A convenient typedef for referring to a pointer to a node object. + */ + typedef ReferenceCountedObjectPtr Ptr; -#endif // __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ -/********* End of inlined file: juce_AudioThumbnailCache.h *********/ + juce_UseDebuggingNewOperator -#endif -#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ + private: + friend class AudioProcessorGraph; -/********* Start of inlined file: juce_FlacAudioFormat.h *********/ -#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ -#define __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ + bool isPrepared; -#if JUCE_USE_FLAC || defined (DOXYGEN) + Node (const uint32 id, AudioProcessor* const processor) throw(); -/** - Reads and writes the lossless-compression FLAC audio format. + void prepare (const double sampleRate, const int blockSize, AudioProcessorGraph* const graph); + void unprepare(); - To compile this, you'll need to set the JUCE_USE_FLAC flag in juce_Config.h, - and make sure your include search path and library search path are set up to find - the FLAC header files and static libraries. + Node (const Node&); + const Node& operator= (const Node&); + }; - @see AudioFormat -*/ -class JUCE_API FlacAudioFormat : public AudioFormat -{ -public: + /** Represents a connection between two channels of two nodes in an AudioProcessorGraph. - FlacAudioFormat(); - ~FlacAudioFormat(); + To create a connection, use AudioProcessorGraph::addConnection(). + */ + struct JUCE_API Connection + { + public: - const Array getPossibleSampleRates(); - const Array getPossibleBitDepths(); - bool canDoStereo(); - bool canDoMono(); - bool isCompressed(); + /** The ID number of the node which is the input source for this connection. + @see AudioProcessorGraph::getNodeForId + */ + uint32 sourceNodeId; - AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails); + /** The index of the output channel of the source node from which this + connection takes its data. - AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex); + If this value is the special number AudioProcessorGraph::midiChannelIndex, then + it is referring to the source node's midi output. Otherwise, it is the zero-based + index of an audio output channel in the source node. + */ + int sourceChannelIndex; - juce_UseDebuggingNewOperator -}; + /** The ID number of the node which is the destination for this connection. + @see AudioProcessorGraph::getNodeForId + */ + uint32 destNodeId; -#endif -#endif // __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_FlacAudioFormat.h *********/ + /** The index of the input channel of the destination node to which this + connection delivers its data. -#endif -#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ + If this value is the special number AudioProcessorGraph::midiChannelIndex, then + it is referring to the destination node's midi input. Otherwise, it is the zero-based + index of an audio input channel in the destination node. + */ + int destChannelIndex; -/********* Start of inlined file: juce_WavAudioFormat.h *********/ -#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ -#define __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ + juce_UseDebuggingNewOperator -/** - Reads and Writes WAV format audio files. + private: + }; - @see AudioFormat -*/ -class JUCE_API WavAudioFormat : public AudioFormat -{ -public: + /** Deletes all nodes and connections from this graph. - /** Creates a format object. */ - WavAudioFormat(); + Any processor objects in the graph will be deleted. + */ + void clear(); - /** Destructor. */ - ~WavAudioFormat(); + /** Returns the number of nodes in the graph. */ + int getNumNodes() const throw() { return nodes.size(); } - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + /** Returns a pointer to one of the nodes in the graph. - @see AudioFormatReader::metadataValues, createWriterFor + This will return 0 if the index is out of range. + @see getNodeForId */ - static const tchar* const bwavDescription; + Node* getNode (const int index) const throw() { return nodes [index]; } - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + /** Searches the graph for a node with the given ID number and returns it. - @see AudioFormatReader::metadataValues, createWriterFor + If no such node was found, this returns 0. + @see getNode */ - static const tchar* const bwavOriginator; - - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + Node* getNodeForId (const uint32 nodeId) const throw(); - @see AudioFormatReader::metadataValues, createWriterFor - */ - static const tchar* const bwavOriginatorRef; + /** Adds a node to the graph. - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + This creates a new node in the graph, for the specified processor. Once you have + added a processor to the graph, the graph owns it and will delete it later when + it is no longer needed. - Date format is: yyyy-mm-dd + The optional nodeId parameter lets you specify an ID to use for the node, but + if the value is already in use, this new node will overwrite the old one. - @see AudioFormatReader::metadataValues, createWriterFor + If this succeeds, it returns a pointer to the newly-created node. */ - static const tchar* const bwavOriginationDate; - - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + Node* addNode (AudioProcessor* const newProcessor, + uint32 nodeId = 0); - Time format is: hh-mm-ss + /** Deletes a node within the graph which has the specified ID. - @see AudioFormatReader::metadataValues, createWriterFor + This will also delete any connections that are attached to this node. */ - static const tchar* const bwavOriginationTime; + bool removeNode (const uint32 nodeId); - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + /** Returns the number of connections in the graph. */ + int getNumConnections() const throw() { return connections.size(); } - This is the number of samples from the start of an edit that the - file is supposed to begin at. Seems like an obvious mistake to - only allow a file to occur in an edit once, but that's the way - it is.. + /** Returns a pointer to one of the connections in the graph. */ + const Connection* getConnection (const int index) const throw() { return connections [index]; } - @see AudioFormatReader::metadataValues, createWriterFor - */ - static const tchar* const bwavTimeReference; + /** Searches for a connection between some specified channels. - /** Metadata property name used by wav readers and writers for adding - a BWAV chunk to the file. + If no such connection is found, this returns 0. + */ + const Connection* getConnectionBetween (const uint32 sourceNodeId, + const int sourceChannelIndex, + const uint32 destNodeId, + const int destChannelIndex) const throw(); - This is a + /** Returns true if there is a connection between any of the channels of + two specified nodes. + */ + bool isConnected (const uint32 possibleSourceNodeId, + const uint32 possibleDestNodeId) const throw(); - @see AudioFormatReader::metadataValues, createWriterFor + /** Returns true if it would be legal to connect the specified points. */ - static const tchar* const bwavCodingHistory; + bool canConnect (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex) const throw(); - /** Utility function to fill out the appropriate metadata for a BWAV file. + /** Attempts to connect two specified channels of two nodes. - This just makes it easier than using the property names directly, and it - fills out the time and date in the right format. + If this isn't allowed (e.g. because you're trying to connect a midi channel + to an audio one or other such nonsense), then it'll return false. */ - static const StringPairArray createBWAVMetadata (const String& description, - const String& originator, - const String& originatorRef, - const Time& dateAndTime, - const int64 timeReferenceSamples, - const String& codingHistory); - - const Array getPossibleSampleRates(); - const Array getPossibleBitDepths(); - bool canDoStereo(); - bool canDoMono(); - - AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails); - - AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex); + bool addConnection (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex); - /** Utility function to replace the metadata in a wav file with a new set of values. + /** Deletes the connection with the specified index. - If possible, this cheats by overwriting just the metadata region of the file, rather - than by copying the whole file again. + Returns true if a connection was actually deleted. */ - bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); - - juce_UseDebuggingNewOperator -}; - -#endif // __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_WavAudioFormat.h *********/ + void removeConnection (const int index); -#endif -#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ + /** Deletes any connection between two specified points. -/********* Start of inlined file: juce_AudioCDReader.h *********/ -#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ -#define __JUCE_AUDIOCDREADER_JUCEHEADER__ + Returns true if a connection was actually deleted. + */ + bool removeConnection (const uint32 sourceNodeId, const int sourceChannelIndex, + const uint32 destNodeId, const int destChannelIndex); -#if JUCE_USE_CDREADER + /** Removes all connections from the specified node. + */ + bool disconnectNode (const uint32 nodeId); -#if JUCE_MAC + /** Performs a sanity checks of all the connections. -#endif + This might be useful if some of the processors are doing things like changing + their channel counts, which could render some connections obsolete. + */ + bool removeIllegalConnections(); -/** - A type of AudioFormatReader that reads from an audio CD. + /** A special number that represents the midi channel of a node. - One of these can be used to read a CD as if it's one big audio stream. Use the - getPositionOfTrackStart() method to find where the individual tracks are - within the stream. + This is used as a channel index value if you want to refer to the midi input + or output instead of an audio channel. + */ + static const int midiChannelIndex; - @see AudioFormatReader -*/ -class JUCE_API AudioCDReader : public AudioFormatReader -{ -public: + /** A special type of AudioProcessor that can live inside an AudioProcessorGraph + in order to use the audio that comes into and out of the graph itself. - /** Returns a list of names of Audio CDs currently available for reading. + If you create an AudioGraphIOProcessor in "input" mode, it will act as a + node in the graph which delivers the audio that is coming into the parent + graph. This allows you to stream the data to other nodes and process the + incoming audio. - If there's a CD drive but no CD in it, this might return an empty list, or - possibly a device that can be opened but which has no tracks, depending - on the platform. + Likewise, one of these in "output" mode can be sent data which it will add to + the sum of data being sent to the graph's output. - @see createReaderForCD + @see AudioProcessorGraph */ - static const StringArray getAvailableCDNames(); - - /** Tries to create an AudioFormatReader that can read from an Audio CD. + class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance + { + public: + /** Specifies the mode in which this processor will operate. + */ + enum IODeviceType + { + audioInputNode, /**< In this mode, the processor has output channels + representing all the audio input channels that are + coming into its parent audio graph. */ + audioOutputNode, /**< In this mode, the processor has input channels + representing all the audio output channels that are + going out of its parent audio graph. */ + midiInputNode, /**< In this mode, the processor has a midi output which + delivers the same midi data that is arriving at its + parent graph. */ + midiOutputNode /**< In this mode, the processor has a midi input and + any data sent to it will be passed out of the parent + graph. */ + }; - @param index the index of one of the available CDs - use getAvailableCDNames() - to find out how many there are. - @returns a new AudioCDReader object, or 0 if it couldn't be created. The - caller will be responsible for deleting the object returned. - */ - static AudioCDReader* createReaderForCD (const int index); + /** Returns the mode of this processor. */ + IODeviceType getType() const throw() { return type; } - /** Destructor. */ - ~AudioCDReader(); + /** Returns the parent graph to which this processor belongs, or 0 if it + hasn't yet been added to one. */ + AudioProcessorGraph* getParentGraph() const throw() { return graph; } - /** Implementation of the AudioFormatReader method. */ - bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, - int64 startSampleInFile, int numSamples); + /** True if this is an audio or midi input. */ + bool isInput() const throw(); + /** True if this is an audio or midi output. */ + bool isOutput() const throw(); - /** Checks whether the CD has been removed from the drive. - */ - bool isCDStillPresent() const; + AudioGraphIOProcessor (const IODeviceType type); + ~AudioGraphIOProcessor(); - /** Returns the total number of tracks (audio + data). - */ - int getNumTracks() const; + const String getName() const; + void fillInPluginDescription (PluginDescription& d) const; - /** Finds the sample offset of the start of a track. + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); - @param trackNum the track number, where 0 is the first track. - */ - int getPositionOfTrackStart (int trackNum) const; + const String getInputChannelName (const int channelIndex) const; + const String getOutputChannelName (const int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; + bool acceptsMidi() const; + bool producesMidi() const; - /** Returns true if a given track is an audio track. + AudioProcessorEditor* createEditor(); - @param trackNum the track number, where 0 is the first track. - */ - bool isTrackAudio (int trackNum) const; + int getNumParameters(); + const String getParameterName (int); + float getParameter (int); + const String getParameterText (int); + void setParameter (int, float); - /** Refreshes the object's table of contents. + int getNumPrograms(); + int getCurrentProgram(); + void setCurrentProgram (int); + const String getProgramName (int); + void changeProgramName (int, const String&); - If the disc has been ejected and a different one put in since this - object was created, this will cause it to update its idea of how many tracks - there are, etc. - */ - void refreshTrackLengths(); + void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); - /** Enables scanning for indexes within tracks. + /** @internal */ + void setParentGraph (AudioProcessorGraph* const graph) throw(); - @see getLastIndex - */ - void enableIndexScanning (bool enabled); + juce_UseDebuggingNewOperator - /** Returns the index number found during the last read() call. + private: + const IODeviceType type; + AudioProcessorGraph* graph; - Index scanning is turned off by default - turn it on with enableIndexScanning(). + AudioGraphIOProcessor (const AudioGraphIOProcessor&); + const AudioGraphIOProcessor& operator= (const AudioGraphIOProcessor&); + }; - Then when the read() method is called, if it comes across an index within that - block, the index number is stored and returned by this method. + // AudioProcessor methods: - Some devices might not support indexes, of course. + const String getName() const; - (If you don't know what CD indexes are, it's unlikely you'll ever need them). + void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); + void releaseResources(); + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); - @see enableIndexScanning - */ - int getLastIndex() const; + const String getInputChannelName (const int channelIndex) const; + const String getOutputChannelName (const int channelIndex) const; + bool isInputChannelStereoPair (int index) const; + bool isOutputChannelStereoPair (int index) const; - /** Scans a track to find the position of any indexes within it. + bool acceptsMidi() const; + bool producesMidi() const; - @param trackNumber the track to look in, where 0 is the first track on the disc - @returns an array of sample positions of any index points found (not including - the index that marks the start of the track) - */ - const Array findIndexesInTrack (const int trackNumber); + AudioProcessorEditor* createEditor() { return 0; } - /** Returns the CDDB id number for the CD. + int getNumParameters() { return 0; } + const String getParameterName (int) { return String::empty; } + float getParameter (int) { return 0; } + const String getParameterText (int) { return String::empty; } + void setParameter (int, float) { } - It's not a great way of identifying a disc, but it's traditional. - */ - int getCDDBId(); + int getNumPrograms() { return 0; } + int getCurrentProgram() { return 0; } + void setCurrentProgram (int) { } + const String getProgramName (int) { return String::empty; } + void changeProgramName (int, const String&) { } - /** Tries to eject the disk. + void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); - Of course this might not be possible, if some other process is using it. - */ - void ejectDisk(); + /** @internal */ + void handleAsyncUpdate(); juce_UseDebuggingNewOperator private: + ReferenceCountedArray nodes; + OwnedArray connections; + int lastNodeId; + AudioSampleBuffer renderingBuffers; + OwnedArray midiBuffers; -#if JUCE_MAC - File volumeDir; - OwnedArray tracks; - Array trackStartSamples; - int currentReaderTrack; - AudioFormatReader* reader; - AudioCDReader (const File& volume); -public: - static int compareElements (const File* const, const File* const) throw(); -private: + CriticalSection renderLock; + VoidArray renderingOps; -#elif JUCE_WINDOWS - int numTracks; - int trackStarts[100]; - bool audioTracks [100]; - void* handle; - bool indexingEnabled; - int lastIndex, firstFrameInBuffer, samplesInBuffer; - MemoryBlock buffer; - AudioCDReader (void* handle); - int getIndexAt (int samplePos); + friend class AudioGraphIOProcessor; + AudioSampleBuffer* currentAudioInputBuffer; + AudioSampleBuffer currentAudioOutputBuffer; + MidiBuffer* currentMidiInputBuffer; + MidiBuffer currentMidiOutputBuffer; -#elif JUCE_LINUX - AudioCDReader(); -#endif + void clearRenderingSequence(); + void buildRenderingSequence(); - AudioCDReader (const AudioCDReader&); - const AudioCDReader& operator= (const AudioCDReader&); + bool isAnInputTo (const uint32 possibleInputId, + const uint32 possibleDestinationId, + const int recursionCheck) const throw(); + + AudioProcessorGraph (const AudioProcessorGraph&); + const AudioProcessorGraph& operator= (const AudioProcessorGraph&); }; -#endif -#endif // __JUCE_AUDIOCDREADER_JUCEHEADER__ -/********* End of inlined file: juce_AudioCDReader.h *********/ +#endif // __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ +/********* End of inlined file: juce_AudioProcessorGraph.h *********/ #endif -#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ +#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ -/********* Start of inlined file: juce_OggVorbisAudioFormat.h *********/ -#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ -#define __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ +#endif +#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ -#if JUCE_USE_OGGVORBIS || defined (DOXYGEN) +/********* Start of inlined file: juce_AudioProcessorPlayer.h *********/ +#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ +#define __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ /** - Reads and writes the Ogg-Vorbis audio format. + An AudioIODeviceCallback object which streams audio through an AudioProcessor. - To compile this, you'll need to set the JUCE_USE_OGGVORBIS flag in juce_Config.h, - and make sure your include search path and library search path are set up to find - the Vorbis and Ogg header files and static libraries. + To use one of these, just make it the callback used by your AudioIODevice, and + give it a processor to use by calling setProcessor(). - @see AudioFormat, + It's also a MidiInputCallback, so you can connect it to both an audio and midi + input to send both streams through the processor. + + @see AudioProcessor, AudioProcessorGraph */ -class JUCE_API OggVorbisAudioFormat : public AudioFormat +class JUCE_API AudioProcessorPlayer : public AudioIODeviceCallback, + public MidiInputCallback { public: - OggVorbisAudioFormat(); - ~OggVorbisAudioFormat(); + /** + */ + AudioProcessorPlayer(); - const Array getPossibleSampleRates(); - const Array getPossibleBitDepths(); - bool canDoStereo(); - bool canDoMono(); - bool isCompressed(); - const StringArray getQualityOptions(); + /** Destructor. */ + virtual ~AudioProcessorPlayer(); - /** Tries to estimate the quality level of an ogg file based on its size. + /** Sets the processor that should be played. - If it can't read the file for some reason, this will just return 1 (medium quality), - otherwise it will return the approximate quality setting that would have been used - to create the file. + The processor that is passed in will not be deleted or owned by this object. + To stop anything playing, pass in 0 to this method. + */ + void setProcessor (AudioProcessor* const processorToPlay); - @see getQualityOptions + /** Returns the current audio processor that is being played. */ - int estimateOggFileQuality (const File& source); + AudioProcessor* getCurrentProcessor() const throw() { return processor; } - AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails); + /** Returns a midi message collector that you can pass midi messages to if you + want them to be injected into the midi stream that is being sent to the + processor. + */ + MidiMessageCollector& getMidiMessageCollector() throw() { return messageCollector; } - AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex); + /** @internal */ + void audioDeviceIOCallback (const float** inputChannelData, + int totalNumInputChannels, + float** outputChannelData, + int totalNumOutputChannels, + int numSamples); + /** @internal */ + void audioDeviceAboutToStart (AudioIODevice* device); + /** @internal */ + void audioDeviceStopped(); + /** @internal */ + void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message); juce_UseDebuggingNewOperator -}; -#endif -#endif // __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_OggVorbisAudioFormat.h *********/ - -#endif -#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ - -/********* Start of inlined file: juce_QuickTimeAudioFormat.h *********/ -#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ -#define __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ - -#if JUCE_QUICKTIME - -/** - Uses QuickTime to read the audio track a movie or media file. +private: + AudioProcessor* processor; + CriticalSection lock; + double sampleRate; + int blockSize; + bool isPrepared; - As well as QuickTime movies, this should also manage to open other audio - files that quicktime can understand, like mp3, m4a, etc. + int numInputChans, numOutputChans; + float* channels [128]; + AudioSampleBuffer tempBuffer; - @see AudioFormat -*/ -class JUCE_API QuickTimeAudioFormat : public AudioFormat -{ -public: + MidiBuffer incomingMidi; + MidiMessageCollector messageCollector; - /** Creates a format object. */ - QuickTimeAudioFormat(); + AudioProcessorPlayer (const AudioProcessorPlayer&); + const AudioProcessorPlayer& operator= (const AudioProcessorPlayer&); +}; - /** Destructor. */ - ~QuickTimeAudioFormat(); +#endif // __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ +/********* End of inlined file: juce_AudioProcessorPlayer.h *********/ - const Array getPossibleSampleRates(); - const Array getPossibleBitDepths(); - bool canDoStereo(); - bool canDoMono(); +#endif +#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ - AudioFormatReader* createReaderFor (InputStream* sourceStream, - const bool deleteStreamIfOpeningFails); +/********* Start of inlined file: juce_GenericAudioProcessorEditor.h *********/ +#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ +#define __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ - AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, - double sampleRateToUse, - unsigned int numberOfChannels, - int bitsPerSample, - const StringPairArray& metadataValues, - int qualityOptionIndex); +/********* Start of inlined file: juce_PropertyPanel.h *********/ +#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ +#define __JUCE_PROPERTYPANEL_JUCEHEADER__ - juce_UseDebuggingNewOperator -}; +/********* Start of inlined file: juce_PropertyComponent.h *********/ +#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ -#endif -#endif // __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_QuickTimeAudioFormat.h *********/ +class EditableProperty; -#endif -#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ +/** + A base class for a component that goes in a PropertyPanel and displays one of + an item's properties. -/********* Start of inlined file: juce_AudioCDBurner.h *********/ -#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ -#define __JUCE_AUDIOCDBURNER_JUCEHEADER__ + Subclasses of this are used to display a property in various forms, e.g. a + ChoicePropertyComponent shows its value as a combo box; a SliderPropertyComponent + shows its value as a slider; a TextPropertyComponent as a text box, etc. -#if JUCE_USE_CDBURNER + A subclass must implement the refresh() method which will be called to tell the + component to update itself, and is also responsible for calling this it when the + item that it refers to is changed. -/** + @see PropertyPanel, TextPropertyComponent, SliderPropertyComponent, + ChoicePropertyComponent, ButtonPropertyComponent, BooleanPropertyComponent */ -class AudioCDBurner +class JUCE_API PropertyComponent : public Component, + public SettableTooltipClient { public: - /** Returns a list of available optical drives. - - Use openDevice() to open one of the items from this list. - */ - static const StringArray findAvailableDevices(); - - /** Tries to open one of the optical drives. + /** Creates a PropertyComponent. - The deviceIndex is an index into the array returned by findAvailableDevices(). + @param propertyName the name is stored as this component's name, and is + used as the name displayed next to this component in + a property panel + @param preferredHeight the height that the component should be given - some + items may need to be larger than a normal row height. + This value can also be set if a subclass changes the + preferredHeight member variable. */ - static AudioCDBurner* openDevice (const int deviceIndex); + PropertyComponent (const String& propertyName, + const int preferredHeight = 25); /** Destructor. */ - ~AudioCDBurner(); + ~PropertyComponent(); - /** Returns true if there's a writable disk in the drive. + /** Returns this item's preferred height. + + This value is specified either in the constructor or by a subclass changing the + preferredHeight member variable. */ - bool isDiskPresent() const; + int getPreferredHeight() const throw() { return preferredHeight; } - /** Returns the number of free blocks on the disk. + /** Updates the property component if the item it refers to has changed. - There are 75 blocks per second, at 44100Hz. + A subclass must implement this method, and other objects may call it to + force it to refresh itself. + + The subclass should be economical in the amount of work is done, so for + example it should check whether it really needs to do a repaint rather than + just doing one every time this method is called, as it may be called when + the value being displayed hasn't actually changed. */ - int getNumAvailableAudioBlocks() const; + virtual void refresh() = 0; - /** Adds a track to be written. + /** The default paint method fills the background and draws a label for the + item's name. - The source passed-in here will be kept by this object, and it will - be used and deleted at some point in the future, either during the - burn() method or when this AudioCDBurner object is deleted. Your caller - method shouldn't keep a reference to it or use it again after passing - it in here. + @see LookAndFeel::drawPropertyComponentBackground(), LookAndFeel::drawPropertyComponentLabel() */ - bool addAudioTrack (AudioSource* source, int numSamples); + void paint (Graphics& g); - /** - - Return true to cancel the current burn operation + /** The default resize method positions any child component to the right of this + one, based on the look and feel's default label size. */ - class BurnProgressListener - { - public: - BurnProgressListener() throw() {} - virtual ~BurnProgressListener() {} - - /** Called at intervals to report on the progress of the AudioCDBurner. - - To cancel the burn, return true from this. - */ - virtual bool audioCDBurnProgress (float proportionComplete) = 0; - }; + void resized(); - const String burn (BurnProgressListener* listener, - const bool ejectDiscAfterwards, - const bool peformFakeBurnForTesting); + /** By default, this just repaints the component. */ + void enablementChanged(); juce_UseDebuggingNewOperator -private: - AudioCDBurner (const int deviceIndex); +protected: + /** Used by the PropertyPanel to determine how high this component needs to be. - void* internal; + A subclass can update this value in its constructor but shouldn't alter it later + as changes won't necessarily be picked up. + */ + int preferredHeight; }; -#endif -#endif // __JUCE_AUDIOCDBURNER_JUCEHEADER__ -/********* End of inlined file: juce_AudioCDBurner.h *********/ - -#endif -#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ - -/********* Start of inlined file: juce_ActionBroadcaster.h *********/ -#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ -#define __JUCE_ACTIONBROADCASTER_JUCEHEADER__ - -/********* Start of inlined file: juce_ActionListenerList.h *********/ -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ -#define __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ +#endif // __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_PropertyComponent.h *********/ /** - A set of ActionListeners. + A panel that holds a list of PropertyComponent objects. - Listeners can be added and removed from the list, and messages can be - broadcast to all the listeners. + This panel displays a list of PropertyComponents, and allows them to be organised + into collapsible sections. - @see ActionListener, ActionBroadcaster + To use, simply create one of these and add your properties to it with addProperties() + or addSection(). + + @see PropertyComponent */ -class JUCE_API ActionListenerList : public MessageListener +class JUCE_API PropertyPanel : public Component { public: - /** Creates an empty list. */ - ActionListenerList() throw(); + /** Creates an empty property panel. */ + PropertyPanel(); /** Destructor. */ - ~ActionListenerList() throw(); - - /** Adds a listener to the list. + ~PropertyPanel(); - (Trying to add a listener that's already on the list will have no effect). + /** Deletes all property components from the panel. */ - void addActionListener (ActionListener* const listener) throw(); + void clear(); - /** Removes a listener from the list. + /** Adds a set of properties to the panel. - If the listener isn't on the list, this won't have any effect. + The components in the list will be owned by this object and will be automatically + deleted later on when no longer needed. + + These properties are added without them being inside a named section. If you + want them to be kept together in a collapsible section, use addSection() instead. */ - void removeActionListener (ActionListener* const listener) throw(); + void addProperties (const Array & newPropertyComponents); - /** Removes all listeners from the list. */ - void removeAllActionListeners() throw(); + /** Adds a set of properties to the panel. - /** Broadcasts a message to all the registered listeners. + These properties are added at the bottom of the list, under a section heading with + a plus/minus button that allows it to be opened and closed. - This sends the message asynchronously. + The components in the list will be owned by this object and will be automatically + deleted later on when no longer needed. - If a listener is on the list when this method is called but is removed from - the list before the message arrives, it won't receive the message. Similarly - listeners that are added to the list after the message is sent but before it - arrives won't get the message either. + To add properies without them being in a section, use addProperties(). */ - void sendActionMessage (const String& message) const; - - /** @internal */ - void handleMessage (const Message&); + void addSection (const String& sectionTitle, + const Array & newPropertyComponents, + const bool shouldSectionInitiallyBeOpen = true); - juce_UseDebuggingNewOperator + /** Calls the refresh() method of all PropertyComponents in the panel */ + void refreshAll() const; -private: - SortedSet actionListeners_; - CriticalSection actionListenerLock_; + /** Returns a list of all the names of sections in the panel. - ActionListenerList (const ActionListenerList&); - const ActionListenerList& operator= (const ActionListenerList&); -}; + These are the sections that have been added with addSection(). + */ + const StringArray getSectionNames() const; -#endif // __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ -/********* End of inlined file: juce_ActionListenerList.h *********/ + /** Returns true if the section at this index is currently open. -/** Manages a list of ActionListeners, and can send them messages. + The index is from 0 up to the number of items returned by getSectionNames(). + */ + bool isSectionOpen (const int sectionIndex) const; - To quickly add methods to your class that can add/remove action - listeners and broadcast to them, you can derive from this. + /** Opens or closes one of the sections. - @see ActionListenerList, ActionListener -*/ -class JUCE_API ActionBroadcaster -{ -public: + The index is from 0 up to the number of items returned by getSectionNames(). + */ + void setSectionOpen (const int sectionIndex, const bool shouldBeOpen); - /** Creates an ActionBroadcaster. */ - ActionBroadcaster() throw(); + /** Enables or disables one of the sections. - /** Destructor. */ - virtual ~ActionBroadcaster(); + The index is from 0 up to the number of items returned by getSectionNames(). + */ + void setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled); - /** Adds a listener to the list. + /** Saves the current state of open/closed sections so it can be restored later. - (Trying to add a listener that's already on the list will have no effect). - */ - void addActionListener (ActionListener* const listener); + The caller is responsible for deleting the object that is returned. - /** Removes a listener from the list. + To restore this state, use restoreOpennessState(). - If the listener isn't on the list, this won't have any effect. + @see restoreOpennessState */ - void removeActionListener (ActionListener* const listener); + XmlElement* getOpennessState() const; - /** Removes all listeners from the list. */ - void removeAllActionListeners(); + /** Restores a previously saved arrangement of open/closed sections. - /** Broadcasts a message to all the registered listeners. + This will try to restore a snapshot of the panel's state that was created by + the getOpennessState() method. If any of the sections named in the original + XML aren't present, they will be ignored. - @see ActionListenerList::sendActionMessage + @see getOpennessState */ - void sendActionMessage (const String& message) const; - -private: + void restoreOpennessState (const XmlElement& newState); - ActionListenerList actionListenerList; + /** Sets a message to be displayed when there are no properties in the panel. - ActionBroadcaster (const ActionBroadcaster&); - const ActionBroadcaster& operator= (const ActionBroadcaster&); -}; + The default message is "nothing selected". + */ + void setMessageWhenEmpty (const String& newMessage); -#endif // __JUCE_ACTIONBROADCASTER_JUCEHEADER__ -/********* End of inlined file: juce_ActionBroadcaster.h *********/ + /** Returns the message that is displayed when there are no properties. + @see setMessageWhenEmpty + */ + const String& getMessageWhenEmpty() const throw(); -#endif -#ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); -#endif -#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ + juce_UseDebuggingNewOperator -#endif -#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ +private: + Viewport* viewport; + Component* propertyHolderComponent; + String messageWhenEmpty; -#endif -#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ + void updatePropHolderLayout() const; + void updatePropHolderLayout (const int width) const; +}; -/********* Start of inlined file: juce_CallbackMessage.h *********/ -#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ -#define __JUCE_CALLBACKMESSAGE_JUCEHEADER__ +#endif // __JUCE_PROPERTYPANEL_JUCEHEADER__ +/********* End of inlined file: juce_PropertyPanel.h *********/ /** - A message that calls a custom function when it gets delivered. - - You can use this class to fire off actions that you want to be performed later - on the message thread. + A type of UI component that displays the parameters of an AudioProcessor as + a simple list of sliders. - Unlike other Message objects, these don't get sent to a MessageListener, you - just call the post() method to send them, and when they arrive, your - messageCallback() method will automatically be invoked. + This can be used for showing an editor for a processor that doesn't supply + its own custom editor. - @see MessageListener, MessageManager, ActionListener, ChangeListener + @see AudioProcessor */ -class JUCE_API CallbackMessage : public Message +class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor { public: - CallbackMessage() throw(); - - /** Destructor. */ - ~CallbackMessage() throw(); - - /** Called when the message is delivered. - - You should implement this method and make it do whatever action you want - to perform. - - Note that like all other messages, this object will be deleted immediately - after this method has been invoked. - */ - virtual void messageCallback() = 0; - - /** Instead of sending this message to a MessageListener, just call this method - to post it to the event queue. + GenericAudioProcessorEditor (AudioProcessor* const owner); + ~GenericAudioProcessorEditor(); - After you've called this, this object will belong to the MessageManager, - which will delete it later. So make sure you don't delete the object yourself, - call post() more than once, or call post() on a stack-based obect! - */ - void post(); + void paint (Graphics& g); + void resized(); juce_UseDebuggingNewOperator private: - CallbackMessage (const CallbackMessage&); - const CallbackMessage& operator= (const CallbackMessage&); + PropertyPanel* panel; }; -#endif // __JUCE_CALLBACKMESSAGE_JUCEHEADER__ -/********* End of inlined file: juce_CallbackMessage.h *********/ - -#endif -#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ - -#endif -#ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ - -#endif -#ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ +#endif // __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ +/********* End of inlined file: juce_GenericAudioProcessorEditor.h *********/ #endif -#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ +#ifndef __JUCE_SAMPLER_JUCEHEADER__ -/********* Start of inlined file: juce_InterprocessConnection.h *********/ -#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ -#define __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ +/********* Start of inlined file: juce_Sampler.h *********/ +#ifndef __JUCE_SAMPLER_JUCEHEADER__ +#define __JUCE_SAMPLER_JUCEHEADER__ -class InterprocessConnectionServer; +/********* Start of inlined file: juce_Synthesiser.h *********/ +#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ +#define __JUCE_SYNTHESISER_JUCEHEADER__ /** - Manages a simple two-way messaging connection to another process, using either - a socket or a named pipe as the transport medium. - - To connect to a waiting socket or an open pipe, use the connectToSocket() or - connectToPipe() methods. If this succeeds, messages can be sent to the other end, - and incoming messages will result in a callback via the messageReceived() - method. + Describes one of the sounds that a Synthesiser can play. - To open a pipe and wait for another client to connect to it, use the createPipe() - method. + A synthesiser can contain one or more sounds, and a sound can choose which + midi notes and channels can trigger it. - To act as a socket server and create connections for one or more client, see the - InterprocessConnectionServer class. + The SynthesiserSound is a passive class that just describes what the sound is - + the actual audio rendering for a sound is done by a SynthesiserVoice. This allows + more than one SynthesiserVoice to play the same sound at the same time. - @see InterprocessConnectionServer, Socket, NamedPipe + @see Synthesiser, SynthesiserVoice */ -class JUCE_API InterprocessConnection : public Thread, - private MessageListener +class JUCE_API SynthesiserSound : public ReferenceCountedObject { -public: +protected: - /** Creates a connection. + SynthesiserSound(); - Connections are created manually, connecting them with the connectToSocket() - or connectToPipe() methods, or they are created automatically by a InterprocessConnectionServer - when a client wants to connect. +public: + /** Destructor. */ + virtual ~SynthesiserSound(); - @param callbacksOnMessageThread if true, callbacks to the connectionMade(), - connectionLost() and messageReceived() methods will - always be made using the message thread; if false, - these will be called immediately on the connection's - own thread. - @param magicMessageHeaderNumber a magic number to use in the header to check the - validity of the data blocks being sent and received. This - can be any number, but the sender and receiver must obviously - use matching values or they won't recognise each other. - */ - InterprocessConnection (const bool callbacksOnMessageThread = true, - const uint32 magicMessageHeaderNumber = 0xf2b49e2c); + /** Returns true if this sound should be played when a given midi note is pressed. - /** Destructor. */ - ~InterprocessConnection(); + The Synthesiser will use this information when deciding which sounds to trigger + for a given note. + */ + virtual bool appliesToNote (const int midiNoteNumber) = 0; - /** Tries to connect this object to a socket. + /** Returns true if the sound should be triggered by midi events on a given channel. - For this to work, the machine on the other end needs to have a InterprocessConnectionServer - object waiting to receive client connections on this port number. + The Synthesiser will use this information when deciding which sounds to trigger + for a given note. + */ + virtual bool appliesToChannel (const int midiChannel) = 0; - @param hostName the host computer, either a network address or name - @param portNumber the socket port number to try to connect to - @param timeOutMillisecs how long to keep trying before giving up - @returns true if the connection is established successfully - @see Socket + /** */ - bool connectToSocket (const String& hostName, - const int portNumber, - const int timeOutMillisecs); + typedef ReferenceCountedObjectPtr Ptr; - /** Tries to connect the object to an existing named pipe. + juce_UseDebuggingNewOperator +}; - For this to work, another process on the same computer must already have opened - an InterprocessConnection object and used createPipe() to create a pipe for this - to connect to. +/** + Represents a voice that a Synthesiser can use to play a SynthesiserSound. - You can optionally specify a timeout length to be passed to the NamedPipe::read() method. + A voice plays a single sound at a time, and a synthesiser holds an array of + voices so that it can play polyphonically. - @returns true if it connects successfully. - @see createPipe, NamedPipe - */ - bool connectToPipe (const String& pipeName, - const int pipeReceiveMessageTimeoutMs = -1); + @see Synthesiser, SynthesiserSound +*/ +class JUCE_API SynthesiserVoice +{ +public: - /** Tries to create a new pipe for other processes to connect to. + /** Creates a voice. */ + SynthesiserVoice(); - This creates a pipe with the given name, so that other processes can use - connectToPipe() to connect to the other end. + /** Destructor. */ + virtual ~SynthesiserVoice(); - You can optionally specify a timeout length to be passed to the NamedPipe::read() method. + /** Returns the midi note that this voice is currently playing. - If another process is already using this pipe, this will fail and return false. + Returns a value less than 0 if no note is playing. */ - bool createPipe (const String& pipeName, - const int pipeReceiveMessageTimeoutMs = -1); + int getCurrentlyPlayingNote() const throw() { return currentlyPlayingNote; } - /** Disconnects and closes any currently-open sockets or pipes. */ - void disconnect(); + /** Returns the sound that this voice is currently playing. - /** True if a socket or pipe is currently active. */ - bool isConnected() const; + Returns 0 if it's not playing. + */ + const SynthesiserSound::Ptr getCurrentlyPlayingSound() const throw() { return currentlyPlayingSound; } - /** Returns the socket that this connection is using (or null if it uses a pipe). */ - StreamingSocket* getSocket() const throw() { return socket; } + /** Must return true if this voice object is capable of playing the given sound. - /** Returns the pipe that this connection is using (or null if it uses a socket). */ - NamedPipe* getPipe() const throw() { return pipe; } + If there are different classes of sound, and different classes of voice, a voice can + choose which ones it wants to take on. - /** Returns the name of the machine at the other end of this connection. + A typical implementation of this method may just return true if there's only one type + of voice and sound, or it might check the type of the sound object passed-in and + see if it's one that it understands. + */ + virtual bool canPlaySound (SynthesiserSound* sound) = 0; - This will return an empty string if the other machine isn't known for - some reason. + /** Called to start a new note. + + This will be called during the rendering callback, so must be fast and thread-safe. */ - const String getConnectedHostName() const; + virtual void startNote (const int midiNoteNumber, + const float velocity, + SynthesiserSound* sound, + const int currentPitchWheelPosition) = 0; - /** Tries to send a message to the other end of this connection. + /** Called to stop a note. - This will fail if it's not connected, or if there's some kind of write error. If - it succeeds, the connection object at the other end will receive the message by - a callback to its messageReceived() method. + This will be called during the rendering callback, so must be fast and thread-safe. - @see messageReceived + If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all + sound immediately, and must call clearCurrentNote() to reset the state of this voice + and allow the synth to reassign it another sound. + + If allowTailOff is true and the voice decides to do a tail-off, then it's allowed to + begin fading out its sound, and it can stop playing until it's finished. As soon as it + finishes playing (during the rendering callback), it must make sure that it calls + clearCurrentNote(). */ - bool sendMessage (const MemoryBlock& message); + virtual void stopNote (const bool allowTailOff) = 0; - /** Called when the connection is first connected. + /** Called to let the voice know that the pitch wheel has been moved. - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. + This will be called during the rendering callback, so must be fast and thread-safe. */ - virtual void connectionMade() = 0; + virtual void pitchWheelMoved (const int newValue) = 0; - /** Called when the connection is broken. + /** Called to let the voice know that a midi controller has been moved. - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. + This will be called during the rendering callback, so must be fast and thread-safe. */ - virtual void connectionLost() = 0; + virtual void controllerMoved (const int controllerNumber, + const int newValue) = 0; - /** Called when a message arrives. + /** Renders the next block of data for this voice. - When the object at the other end of this connection sends us a message with sendMessage(), - this callback is used to deliver it to us. + The output audio data must be added to the current contents of the buffer provided. + Only the region of the buffer between startSample and (startSample + numSamples) + should be altered by this method. - If the connection was created with the callbacksOnMessageThread flag set, then - this will be called on the message thread; otherwise it will be called on a server - thread. + If the voice is currently silent, it should just return without doing anything. - @see sendMessage + If the sound that the voice is playing finishes during the course of this rendered + block, it must call clearCurrentNote(), to tell the synthesiser that it has finished. + + The size of the blocks that are rendered can change each time it is called, and may + involve rendering as little as 1 sample at a time. In between rendering callbacks, + the voice's methods will be called to tell it about note and controller events. */ - virtual void messageReceived (const MemoryBlock& message) = 0; + virtual void renderNextBlock (AudioSampleBuffer& outputBuffer, + int startSample, + int numSamples) = 0; - juce_UseDebuggingNewOperator + /** Returns true if the voice is currently playing a sound which is mapped to the given + midi channel. -private: - CriticalSection pipeAndSocketLock; - StreamingSocket* socket; - NamedPipe* pipe; - bool callbackConnectionState; - const bool useMessageThread; - const uint32 magicMessageHeader; - int pipeReceiveMessageTimeout; + If it's not currently playing, this will return false. + */ + bool isPlayingChannel (const int midiChannel) const; - friend class InterprocessConnectionServer; + /** Changes the voice's reference sample rate. - void initialiseWithSocket (StreamingSocket* const socket_); - void initialiseWithPipe (NamedPipe* const pipe_); + The rate is set so that subclasses know the output rate and can set their pitch + accordingly. - void handleMessage (const Message& message); + This method is called by the synth, and subclasses can access the current rate with + the currentSampleRate member. + */ + void setCurrentPlaybackSampleRate (const double newRate); - void connectionMadeInt(); - void connectionLostInt(); - void deliverDataInt (const MemoryBlock& data); + juce_UseDebuggingNewOperator - bool readNextMessageInt(); - void run(); +protected: - InterprocessConnection (const InterprocessConnection&); - const InterprocessConnection& operator= (const InterprocessConnection&); -}; + /** Returns the current target sample rate at which rendering is being done. -#endif // __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ -/********* End of inlined file: juce_InterprocessConnection.h *********/ + This is available for subclasses so they can pitch things correctly. + */ + double getSampleRate() const throw() { return currentSampleRate; } -#endif -#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ + /** Resets the state of this voice after a sound has finished playing. -/********* Start of inlined file: juce_InterprocessConnectionServer.h *********/ -#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ -#define __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ - -/** - An object that waits for client sockets to connect to a port on this host, and - creates InterprocessConnection objects for each one. - - To use this, create a class derived from it which implements the createConnectionObject() - method, so that it creates suitable connection objects for each client that tries - to connect. + The subclass must call this when it finishes playing a note and becomes available + to play new ones. - @see InterprocessConnection -*/ -class JUCE_API InterprocessConnectionServer : private Thread -{ -public: + It must either call it in the stopNote() method, or if the voice is tailing off, + then it should call it later during the renderNextBlock method, as soon as it + finishes its tail-off. - /** Creates an uninitialised server object. + It can also be called at any time during the render callback if the sound happens + to have finished, e.g. if it's playing a sample and the sample finishes. */ - InterprocessConnectionServer(); - - /** Destructor. */ - ~InterprocessConnectionServer(); - - /** Starts an internal thread which listens on the given port number. + void clearCurrentNote(); - While this is running, in another process tries to connect with the - InterprocessConnection::connectToSocket() method, this object will call - createConnectionObject() to create a connection to that client. +private: - Use stop() to stop the thread running. + friend class Synthesiser; - @see createConnectionObject, stop - */ - bool beginWaitingForSocket (const int portNumber); + double currentSampleRate; + int currentlyPlayingNote; + uint32 noteOnTime; + SynthesiserSound::Ptr currentlyPlayingSound; +}; - /** Terminates the listener thread, if it's active. +/** + Base class for a musical device that can play sounds. - @see beginWaitingForSocket - */ - void stop(); + To create a synthesiser, you'll need to create a subclass of SynthesiserSound + to describe each sound available to your synth, and a subclass of SynthesiserVoice + which can play back one of these sounds. -protected: - /** Creates a suitable connection object for a client process that wants to - connect to this one. + Then you can use the addVoice() and addSound() methods to give the synthesiser a + set of sounds, and a set of voices it can use to play them. If you only give it + one voice it will be monophonic - the more voices it has, the more polyphony it'll + have available. - This will be called by the listener thread when a client process tries - to connect, and must return a new InterprocessConnection object that will - then run as this end of the connection. + Then repeatedly call the renderNextBlock() method to produce the audio. Any midi + events that go in will be scanned for note on/off messages, and these are used to + start and stop the voices playing the appropriate sounds. - @see InterprocessConnection - */ - virtual InterprocessConnection* createConnectionObject() = 0; + While it's playing, you can also cause notes to be triggered by calling the noteOn(), + noteOff() and other controller methods. + Before rendering, be sure to call the setCurrentPlaybackSampleRate() to tell it + what the target playback rate is. This value is passed on to the voices so that + they can pitch their output correctly. +*/ +class JUCE_API Synthesiser +{ public: - juce_UseDebuggingNewOperator - -private: - StreamingSocket* volatile socket; - - void run(); + /** Creates a new synthesiser. - InterprocessConnectionServer (const InterprocessConnectionServer&); - const InterprocessConnectionServer& operator= (const InterprocessConnectionServer&); -}; + You'll need to add some sounds and voices before it'll make any sound.. + */ + Synthesiser(); -#endif // __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ -/********* End of inlined file: juce_InterprocessConnectionServer.h *********/ + /** Destructor. */ + virtual ~Synthesiser(); -#endif -#ifndef __JUCE_MESSAGE_JUCEHEADER__ + /** Deletes all voices. */ + void clearVoices(); -#endif -#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ + /** Returns the number of voices that have been added. */ + int getNumVoices() const throw() { return voices.size(); } -#endif -#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__ + /** Returns one of the voices that have been added. */ + SynthesiserVoice* getVoice (const int index) const throw(); -/********* Start of inlined file: juce_MessageManager.h *********/ -#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__ -#define __JUCE_MESSAGEMANAGER_JUCEHEADER__ + /** Adds a new voice to the synth. -class Component; -class MessageManagerLock; + All the voices should be the same class of object and are treated equally. -/** See MessageManager::callFunctionOnMessageThread() for use of this function type -*/ -typedef void* (MessageCallbackFunction) (void* userData); + The object passed in will be managed by the synthesiser, which will delete + it later on when no longer needed. The caller should not retain a pointer to the + voice. + */ + void addVoice (SynthesiserVoice* const newVoice); -/** Delivers Message objects to MessageListeners, and handles the event-dispatch loop. + /** Deletes one of the voices. */ + void removeVoice (const int index); - @see Message, MessageListener, MessageManagerLock, JUCEApplication -*/ -class JUCE_API MessageManager -{ -public: + /** Deletes all sounds. */ + void clearSounds(); - /** Returns the global instance of the MessageManager. */ - static MessageManager* getInstance() throw(); + /** Returns the number of sounds that have been added to the synth. */ + int getNumSounds() const throw() { return sounds.size(); } - /** Runs the event dispatch loop until a stop message is posted. + /** Returns one of the sounds. */ + SynthesiserSound* getSound (const int index) const throw() { return sounds [index]; } - This method is only intended to be run by the application's startup routine, - as it blocks, and will only return after the stopDispatchLoop() method has been used. + /** Adds a new sound to the synthesiser. - @see stopDispatchLoop + The object passed in is reference counted, so will be deleted when it is removed + from the synthesiser, and when no voices are still using it. */ - void runDispatchLoop(); + void addSound (const SynthesiserSound::Ptr& newSound); - /** Sends a signal that the dispatch loop should terminate. + /** Removes and deletes one of the sounds. */ + void removeSound (const int index); - After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods - will be interrupted and will return. + /** If set to true, then the synth will try to take over an existing voice if + it runs out and needs to play another note. - @see runDispatchLoop + The value of this boolean is passed into findFreeVoice(), so the result will + depend on the implementation of this method. */ - void stopDispatchLoop(); + void setNoteStealingEnabled (const bool shouldStealNotes); - /** Returns true if the stopDispatchLoop() method has been called. + /** Returns true if note-stealing is enabled. + @see setNoteStealingEnabled */ - bool hasStopMessageBeenSent() const throw() { return quitMessagePosted; } + bool isNoteStealingEnabled() const throw() { return shouldStealNotes; } - /** Synchronously dispatches messages until a given time has elapsed. + /** Triggers a note-on event. - Returns false if a quit message has been posted by a call to stopDispatchLoop(), - otherwise returns true. + The default method here will find all the sounds that want to be triggered by + this note/channel. For each sound, it'll try to find a free voice, and use the + voice to start playing the sound. + + Subclasses might want to override this if they need a more complex algorithm. + + This method will be called automatically according to the midi data passed into + renderNextBlock(), but may be called explicitly too. */ - bool runDispatchLoopUntil (int millisecondsToRunFor); + virtual void noteOn (const int midiChannel, + const int midiNoteNumber, + const float velocity); - /** Calls a function using the message-thread. + /** Triggers a note-off event. - This can be used by any thread to cause this function to be called-back - by the message thread. If it's the message-thread that's calling this method, - then the function will just be called; if another thread is calling, a message - will be posted to the queue, and this method will block until that message - is delivered, the function is called, and the result is returned. + This will turn off any voices that are playing a sound for the given note/channel. - Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller - thread has a critical section locked, which an unrelated message callback then tries to lock - before the message thread gets round to processing this callback. + If allowTailOff is true, the voices will be allowed to fade out the notes gracefully + (if they can do). If this is false, the notes will all be cut off immediately. - @param callback the function to call - its signature must be @code - void* myCallbackFunction (void*) @endcode - @param userData a user-defined pointer that will be passed to the function that gets called - @returns the value that the callback function returns. - @see MessageManagerLock + This method will be called automatically according to the midi data passed into + renderNextBlock(), but may be called explicitly too. */ - void* callFunctionOnMessageThread (MessageCallbackFunction* callback, - void* userData); + virtual void noteOff (const int midiChannel, + const int midiNoteNumber, + const bool allowTailOff); - /** Returns true if the caller-thread is the message thread. */ - bool isThisTheMessageThread() const throw(); + /** Turns off all notes. - /** Called to tell the manager which thread is the one that's running the dispatch loop. + This will turn off any voices that are playing a sound on the given midi channel. - (Best to ignore this method unless you really know what you're doing..) - @see getCurrentMessageThread - */ - void setCurrentMessageThread (const Thread::ThreadID threadId) throw(); + If midiChannel is 0 or less, then all voices will be turned off, regardless of + which channel they're playing. - /** Returns the ID of the current message thread, as set by setCurrentMessageThread(). + If allowTailOff is true, the voices will be allowed to fade out the notes gracefully + (if they can do). If this is false, the notes will all be cut off immediately. - (Best to ignore this method unless you really know what you're doing..) - @see setCurrentMessageThread + This method will be called automatically according to the midi data passed into + renderNextBlock(), but may be called explicitly too. */ - Thread::ThreadID getCurrentMessageThread() const throw() { return messageThreadId; } + virtual void allNotesOff (const int midiChannel, + const bool allowTailOff); - /** Returns true if the caller thread has currenltly got the message manager locked. + /** Sends a pitch-wheel message. - see the MessageManagerLock class for more info about this. + This will send a pitch-wheel message to any voices that are playing sounds on + the given midi channel. - This will be true if the caller is the message thread, because that automatically - gains a lock while a message is being dispatched. + This method will be called automatically according to the midi data passed into + renderNextBlock(), but may be called explicitly too. + + @param midiChannel the midi channel for the event + @param wheelValue the wheel position, from 0 to 0x3fff, as returned by MidiMessage::getPitchWheelValue() */ - bool currentThreadHasLockedMessageManager() const throw(); + virtual void handlePitchWheel (const int midiChannel, + const int wheelValue); - /** Sends a message to all other JUCE applications that are running. + /** Sends a midi controller message. - @param messageText the string that will be passed to the actionListenerCallback() - method of the broadcast listeners in the other app. - @see registerBroadcastListener, ActionListener - */ - static void broadcastMessage (const String& messageText) throw(); + This will send a midi controller message to any voices that are playing sounds on + the given midi channel. - /** Registers a listener to get told about broadcast messages. + This method will be called automatically according to the midi data passed into + renderNextBlock(), but may be called explicitly too. - The actionListenerCallback() callback's string parameter - is the message passed into broadcastMessage(). + @param midiChannel the midi channel for the event + @param controllerNumber the midi controller type, as returned by MidiMessage::getControllerNumber() + @param controllerValue the midi controller value, between 0 and 127, as returned by MidiMessage::getControllerValue() + */ + virtual void handleController (const int midiChannel, + const int controllerNumber, + const int controllerValue); - @see broadcastMessage + /** Tells the synthesiser what the sample rate is for the audio it's being used to + render. + + This value is propagated to the voices so that they can use it to render the correct + pitches. */ - void registerBroadcastListener (ActionListener* listener) throw(); + void setCurrentPlaybackSampleRate (const double sampleRate); - /** Deregisters a broadcast listener. */ - void deregisterBroadcastListener (ActionListener* listener) throw(); + /** Creates the next block of audio output. - /** @internal */ - void deliverMessage (void*); - /** @internal */ - void deliverBroadcastMessage (const String&); - /** @internal */ - ~MessageManager() throw(); + This will process the next numSamples of data from all the voices, and add that output + to the audio block supplied, starting from the offset specified. Note that the + data will be added to the current contents of the buffer, so you should clear it + before calling this method if necessary. + + The midi events in the inputMidi buffer are parsed for note and controller events, + and these are used to trigger the voices. Note that the startSample offset applies + both to the audio output buffer and the midi input buffer, so any midi events + with timestamps outside the specified region will be ignored. + */ + void renderNextBlock (AudioSampleBuffer& outputAudio, + const MidiBuffer& inputMidi, + int startSample, + int numSamples); juce_UseDebuggingNewOperator -private: - MessageManager() throw(); +protected: - friend class MessageListener; - friend class ChangeBroadcaster; - friend class ActionBroadcaster; - friend class CallbackMessage; - static MessageManager* instance; + /** This is used to control access to the rendering callback and the note trigger methods. */ + CriticalSection lock; - SortedSet messageListeners; - ActionListenerList* broadcastListeners; + OwnedArray voices; + ReferenceCountedArray sounds; - friend class JUCEApplication; - bool quitMessagePosted, quitMessageReceived; - Thread::ThreadID messageThreadId; + /** The last pitch-wheel values for each midi channel. */ + int lastPitchWheelValues [16]; - VoidArray modalComponents; - static void* exitModalLoopCallback (void*); + /** Searches through the voices to find one that's not currently playing, and which + can play the given sound. - void postMessageToQueue (Message* const message); - void postCallbackMessage (Message* const message); + Returns 0 if all voices are busy and stealing isn't enabled. - static void doPlatformSpecificInitialisation(); - static void doPlatformSpecificShutdown(); + This can be overridden to implement custom voice-stealing algorithms. + */ + virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay, + const bool stealIfNoneAvailable) const; - friend class MessageManagerLock; - Thread::ThreadID volatile threadWithLock; - CriticalSection lockingLock; + /** Starts a specified voice playing a particular sound. - MessageManager (const MessageManager&); - const MessageManager& operator= (const MessageManager&); -}; + You'll probably never need to call this, it's used internally by noteOn(), but + may be needed by subclasses for custom behaviours. + */ + void startVoice (SynthesiserVoice* const voice, + SynthesiserSound* const sound, + const int midiChannel, + const int midiNoteNumber, + const float velocity); -/** Used to make sure that the calling thread has exclusive access to the message loop. + /** xxx Temporary method here to cause a compiler error - note the new parameters for this method. */ + int findFreeVoice (const bool) const { return 0; } - Because it's not thread-safe to call any of the Component or other UI classes - from threads other than the message thread, one of these objects can be used to - lock the message loop and allow this to be done. The message thread will be - suspended for the lifetime of the MessageManagerLock object, so create one on - the stack like this: @code - void MyThread::run() - { - someData = 1234; +private: + double sampleRate; + uint32 lastNoteOnCounter; + bool shouldStealNotes; - const MessageManagerLock mmLock; - // the event loop will now be locked so it's safe to make a few calls.. + Synthesiser (const Synthesiser&); + const Synthesiser& operator= (const Synthesiser&); +}; - myComponent->setBounds (newBounds); - myComponent->repaint(); +#endif // __JUCE_SYNTHESISER_JUCEHEADER__ +/********* End of inlined file: juce_Synthesiser.h *********/ - // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope - } - @endcode +/** + A subclass of SynthesiserSound that represents a sampled audio clip. - Obviously be careful not to create one of these and leave it lying around, or - your app will grind to a halt! + This is a pretty basic sampler, and just attempts to load the whole audio stream + into memory. - Another caveat is that using this in conjunction with other CriticalSections - can create lots of interesting ways of producing a deadlock! In particular, if - your message thread calls stopThread() for a thread that uses these locks, - you'll get an (occasional) deadlock.. + To use it, create a Synthesiser, add some SamplerVoice objects to it, then + give it some SampledSound objects to play. - @see MessageManager, MessageManager::currentThreadHasLockedMessageManager + @see SamplerVoice, Synthesiser, SynthesiserSound */ -class JUCE_API MessageManagerLock +class JUCE_API SamplerSound : public SynthesiserSound { public: - /** Tries to acquire a lock on the message manager. + /** Creates a sampled sound from an audio reader. - The constructor attempts to gain a lock on the message loop, and the lock will be - kept for the lifetime of this object. + This will attempt to load the audio from the source into memory and store + it in this object. - Optionally, you can pass a thread object here, and while waiting to obtain the lock, - this method will keep checking whether the thread has been given the - Thread::signalThreadShouldExit() signal. If this happens, then it will return - without gaining the lock. If you pass a thread, you must check whether the lock was - successful by calling lockWasGained(). If this is false, your thread is being told to - die, so you should take evasive action. + @param name a name for the sample + @param source the audio to load. This object can be safely deleted by the + caller after this constructor returns + @param midiNotes the set of midi keys that this sound should be played on. This + is used by the SynthesiserSound::appliesToNote() method + @param midiNoteForNormalPitch the midi note at which the sample should be played + with its natural rate. All other notes will be pitched + up or down relative to this one + @param attackTimeSecs the attack (fade-in) time, in seconds + @param releaseTimeSecs the decay (fade-out) time, in seconds + @param maxSampleLengthSeconds a maximum length of audio to read from the audio + source, in seconds + */ + SamplerSound (const String& name, + AudioFormatReader& source, + const BitArray& midiNotes, + const int midiNoteForNormalPitch, + const double attackTimeSecs, + const double releaseTimeSecs, + const double maxSampleLengthSeconds); - If you pass zero for the thread object, it will wait indefinitely for the lock - be - careful when doing this, because it's very easy to deadlock if your message thread - attempts to call stopThread() on a thread just as that thread attempts to get the - message lock. + /** Destructor. */ + ~SamplerSound(); - If the calling thread already has the lock, nothing will be done, so it's safe and - quick to use these locks recursively. + /** Returns the sample's name */ + const String& getName() const throw() { return name; } - E.g. - @code - void run() - { - ... + /** Returns the audio sample data. + This could be 0 if there was a problem loading it. + */ + AudioSampleBuffer* getAudioData() const throw() { return data; } - while (! threadShouldExit()) - { - MessageManagerLock mml (Thread::getCurrentThread()); + bool appliesToNote (const int midiNoteNumber); + bool appliesToChannel (const int midiChannel); - if (! mml.lockWasGained()) - return; // another thread is trying to kill us! + juce_UseDebuggingNewOperator - ..do some locked stuff here.. - } +private: + friend class SamplerVoice; - ..and now the MM is now unlocked.. - } - @endcode + String name; + AudioSampleBuffer* data; + double sourceSampleRate; + BitArray midiNotes; + int length, attackSamples, releaseSamples; + int midiRootNote; +}; - */ - MessageManagerLock (Thread* const threadToCheckForExitSignal = 0) throw(); +/** + A subclass of SynthesiserVoice that can play a SamplerSound. - /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob - instead of a thread. + To use it, create a Synthesiser, add some SamplerVoice objects to it, then + give it some SampledSound objects to play. - See the MessageManagerLock (Thread*) constructor for details on how this works. + @see SamplerSound, Synthesiser, SynthesiserVoice +*/ +class JUCE_API SamplerVoice : public SynthesiserVoice +{ +public: + + /** Creates a SamplerVoice. */ - MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw(); + SamplerVoice(); - /** Releases the current thread's lock on the message manager. + /** Destructor. */ + ~SamplerVoice(); - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - ~MessageManagerLock() throw(); + bool canPlaySound (SynthesiserSound* sound); - /** Returns true if the lock was successfully acquired. + void startNote (const int midiNoteNumber, + const float velocity, + SynthesiserSound* sound, + const int currentPitchWheelPosition); - (See the constructor that takes a Thread for more info). - */ - bool lockWasGained() const throw() { return locked; } + void stopNote (const bool allowTailOff); -private: - bool locked, needsUnlocking; - void* sharedEvents; + void pitchWheelMoved (const int newValue); + void controllerMoved (const int controllerNumber, + const int newValue); - void init (Thread* const thread, ThreadPoolJob* const job) throw(); + void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples); - MessageManagerLock (const MessageManagerLock&); - const MessageManagerLock& operator= (const MessageManagerLock&); + juce_UseDebuggingNewOperator + +private: + double pitchRatio; + double sourceSamplePosition; + float lgain, rgain, attackReleaseLevel, attackDelta, releaseDelta; + bool isInAttack, isInRelease; }; -#endif // __JUCE_MESSAGEMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_MessageManager.h *********/ +#endif // __JUCE_SAMPLER_JUCEHEADER__ +/********* End of inlined file: juce_Sampler.h *********/ #endif -#ifndef __JUCE_MULTITIMER_JUCEHEADER__ +#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ -/********* Start of inlined file: juce_MultiTimer.h *********/ -#ifndef __JUCE_MULTITIMER_JUCEHEADER__ -#define __JUCE_MULTITIMER_JUCEHEADER__ +#endif +#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ -/** - A type of timer class that can run multiple timers with different frequencies, - all of which share a single callback. +/********* Start of inlined file: juce_ActionBroadcaster.h *********/ +#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ +#define __JUCE_ACTIONBROADCASTER_JUCEHEADER__ - This class is very similar to the Timer class, but allows you run multiple - separate timers, where each one has a unique ID number. The methods in this - class are exactly equivalent to those in Timer, but with the addition of - this ID number. +/********* Start of inlined file: juce_ActionListenerList.h *********/ +#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ +#define __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ - To use it, you need to create a subclass of MultiTimer, implementing the - timerCallback() method. Then you can start timers with startTimer(), and - each time the callback is triggered, it passes in the ID of the timer that - caused it. +/** + A set of ActionListeners. - @see Timer + Listeners can be added and removed from the list, and messages can be + broadcast to all the listeners. + + @see ActionListener, ActionBroadcaster */ -class JUCE_API MultiTimer +class JUCE_API ActionListenerList : public MessageListener { -protected: +public: - /** Creates a MultiTimer. + /** Creates an empty list. */ + ActionListenerList() throw(); - When created, no timers are running, so use startTimer() to start things off. + /** Destructor. */ + ~ActionListenerList() throw(); + + /** Adds a listener to the list. + + (Trying to add a listener that's already on the list will have no effect). */ - MultiTimer() throw(); + void addActionListener (ActionListener* const listener) throw(); - /** Creates a copy of another timer. + /** Removes a listener from the list. - Note that this timer will not contain any running timers, even if the one you're - copying from was running. + If the listener isn't on the list, this won't have any effect. */ - MultiTimer (const MultiTimer& other) throw(); + void removeActionListener (ActionListener* const listener) throw(); -public: + /** Removes all listeners from the list. */ + void removeAllActionListeners() throw(); - /** Destructor. */ - virtual ~MultiTimer(); + /** Broadcasts a message to all the registered listeners. - /** The user-defined callback routine that actually gets called by each of the - timers that are running. + This sends the message asynchronously. - It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. + If a listener is on the list when this method is called but is removed from + the list before the message arrives, it won't receive the message. Similarly + listeners that are added to the list after the message is sent but before it + arrives won't get the message either. */ - virtual void timerCallback (const int timerId) = 0; + void sendActionMessage (const String& message) const; - /** Starts a timer and sets the length of interval required. + /** @internal */ + void handleMessage (const Message&); - If the timer is already started, this will reset it, so the - time between calling this method and the next timer callback - will not be less than the interval length passed in. + juce_UseDebuggingNewOperator - @param timerId a unique Id number that identifies the timer to - start. This is the id that will be passed back - to the timerCallback() method when this timer is - triggered - @param intervalInMilliseconds the interval to use (any values less than 1 will be - rounded up to 1) - */ - void startTimer (const int timerId, const int intervalInMilliseconds) throw(); +private: + SortedSet actionListeners_; + CriticalSection actionListenerLock_; - /** Stops a timer. + ActionListenerList (const ActionListenerList&); + const ActionListenerList& operator= (const ActionListenerList&); +}; - If a timer has been started with the given ID number, it will be cancelled. - No more callbacks will be made for the specified timer after this method returns. +#endif // __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ +/********* End of inlined file: juce_ActionListenerList.h *********/ - If this is called from a different thread, any callbacks that may - be currently executing may be allowed to finish before the method - returns. - */ - void stopTimer (const int timerId) throw(); +/** Manages a list of ActionListeners, and can send them messages. - /** Checks whether a timer has been started for a specified ID. + To quickly add methods to your class that can add/remove action + listeners and broadcast to them, you can derive from this. - @returns true if a timer with the given ID is running. + @see ActionListenerList, ActionListener +*/ +class JUCE_API ActionBroadcaster +{ +public: + + /** Creates an ActionBroadcaster. */ + ActionBroadcaster() throw(); + + /** Destructor. */ + virtual ~ActionBroadcaster(); + + /** Adds a listener to the list. + + (Trying to add a listener that's already on the list will have no effect). */ - bool isTimerRunning (const int timerId) const throw(); + void addActionListener (ActionListener* const listener); - /** Returns the interval for a specified timer ID. + /** Removes a listener from the list. - @returns the timer's interval in milliseconds if it's running, or 0 if it's no timer - is running for the ID number specified. + If the listener isn't on the list, this won't have any effect. */ - int getTimerInterval (const int timerId) const throw(); + void removeActionListener (ActionListener* const listener); -private: - CriticalSection timerListLock; - VoidArray timers; + /** Removes all listeners from the list. */ + void removeAllActionListeners(); - const MultiTimer& operator= (const MultiTimer&); -}; + /** Broadcasts a message to all the registered listeners. -#endif // __JUCE_MULTITIMER_JUCEHEADER__ -/********* End of inlined file: juce_MultiTimer.h *********/ + @see ActionListenerList::sendActionMessage + */ + void sendActionMessage (const String& message) const; -#endif -#ifndef __JUCE_TIMER_JUCEHEADER__ +private: -#endif -#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ + ActionListenerList actionListenerList; -#endif -#ifndef __JUCE_COLOUR_JUCEHEADER__ + ActionBroadcaster (const ActionBroadcaster&); + const ActionBroadcaster& operator= (const ActionBroadcaster&); +}; -#endif -#ifndef __JUCE_COLOURS_JUCEHEADER__ +#endif // __JUCE_ACTIONBROADCASTER_JUCEHEADER__ +/********* End of inlined file: juce_ActionBroadcaster.h *********/ #endif -#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ +#ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ #endif -#ifndef __JUCE_TYPEFACE_JUCEHEADER__ +#ifndef __JUCE_ACTIONLISTENERLIST_JUCEHEADER__ #endif -#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ +#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ -/********* Start of inlined file: juce_TextLayout.h *********/ -#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ -#define __JUCE_TEXTLAYOUT_JUCEHEADER__ +#endif +#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ -class Graphics; +/********* Start of inlined file: juce_CallbackMessage.h *********/ +#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ +#define __JUCE_CALLBACKMESSAGE_JUCEHEADER__ /** - A laid-out arrangement of text. + A message that calls a custom function when it gets delivered. - You can add text in different fonts to a TextLayout object, then call its - layout() method to word-wrap it into lines. The layout can then be drawn - using a graphics context. + You can use this class to fire off actions that you want to be performed later + on the message thread. - It's handy if you've got a message to display, because you can format it, - measure the extent of the layout, and then create a suitably-sized window - to show it in. + Unlike other Message objects, these don't get sent to a MessageListener, you + just call the post() method to send them, and when they arrive, your + messageCallback() method will automatically be invoked. - @see Font, Graphics::drawFittedText, GlyphArrangement + @see MessageListener, MessageManager, ActionListener, ChangeListener */ -class JUCE_API TextLayout +class JUCE_API CallbackMessage : public Message { public: - /** Creates an empty text layout. - - Text can then be appended using the appendText() method. - */ - TextLayout() throw(); - - /** Creates a copy of another layout object. */ - TextLayout (const TextLayout& other) throw(); - - /** Creates a text layout from an initial string and font. */ - TextLayout (const String& text, const Font& font) throw(); + CallbackMessage() throw(); /** Destructor. */ - ~TextLayout() throw(); - - /** Copies another layout onto this one. */ - const TextLayout& operator= (const TextLayout& layoutToCopy) throw(); - - /** Clears the layout, removing all its text. */ - void clear() throw(); - - /** Adds a string to the end of the arrangement. - - The string will be broken onto new lines wherever it contains - carriage-returns or linefeeds. After adding it, you can call layout() - to wrap long lines into a paragraph and justify it. - */ - void appendText (const String& textToAppend, - const Font& fontToUse) throw(); - - /** Replaces all the text with a new string. - - This is equivalent to calling clear() followed by appendText(). - */ - void setText (const String& newText, - const Font& fontToUse) throw(); - - /** Breaks the text up to form a paragraph with the given width. - - @param maximumWidth any text wider than this will be split - across multiple lines - @param justification how the lines are to be laid-out horizontally - @param attemptToBalanceLineLengths if true, it will try to split the lines at a - width that keeps all the lines of text at a - similar length - this is good when you're displaying - a short message and don't want it to get split - onto two lines with only a couple of words on - the second line, which looks untidy. - */ - void layout (int maximumWidth, - const Justification& justification, - const bool attemptToBalanceLineLengths) throw(); - - /** Returns the overall width of the entire text layout. */ - int getWidth() const throw(); - - /** Returns the overall height of the entire text layout. */ - int getHeight() const throw(); - - /** Returns the total number of lines of text. */ - int getNumLines() const throw() { return totalLines; } + ~CallbackMessage() throw(); - /** Returns the width of a particular line of text. + /** Called when the message is delivered. - @param lineNumber the line, from 0 to (getNumLines() - 1) - */ - int getLineWidth (const int lineNumber) const throw(); + You should implement this method and make it do whatever action you want + to perform. - /** Renders the text at a specified position using a graphics context. + Note that like all other messages, this object will be deleted immediately + after this method has been invoked. */ - void draw (Graphics& g, - const int topLeftX, - const int topLeftY) const throw(); + virtual void messageCallback() = 0; - /** Renders the text within a specified rectangle using a graphics context. + /** Instead of sending this message to a MessageListener, just call this method + to post it to the event queue. - The justification flags dictate how the block of text should be positioned - within the rectangle. + After you've called this, this object will belong to the MessageManager, + which will delete it later. So make sure you don't delete the object yourself, + call post() more than once, or call post() on a stack-based obect! */ - void drawWithin (Graphics& g, - int x, int y, int w, int h, - const Justification& layoutFlags) const throw(); + void post(); juce_UseDebuggingNewOperator private: - VoidArray tokens; - int totalLines; + CallbackMessage (const CallbackMessage&); + const CallbackMessage& operator= (const CallbackMessage&); }; -#endif // __JUCE_TEXTLAYOUT_JUCEHEADER__ -/********* End of inlined file: juce_TextLayout.h *********/ +#endif // __JUCE_CALLBACKMESSAGE_JUCEHEADER__ +/********* End of inlined file: juce_CallbackMessage.h *********/ #endif -#ifndef __JUCE_FONT_JUCEHEADER__ +#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ #endif -#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ +#ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ -/********* Start of inlined file: juce_GlyphArrangement.h *********/ -#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ -#define __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ +#endif +#ifndef __JUCE_CHANGELISTENERLIST_JUCEHEADER__ + +#endif +#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ + +/********* Start of inlined file: juce_InterprocessConnection.h *********/ +#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ +#define __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ + +class InterprocessConnectionServer; /** - A glyph from a particular font, with a particular size, style, - typeface and position. + Manages a simple two-way messaging connection to another process, using either + a socket or a named pipe as the transport medium. - @see GlyphArrangement, Font + To connect to a waiting socket or an open pipe, use the connectToSocket() or + connectToPipe() methods. If this succeeds, messages can be sent to the other end, + and incoming messages will result in a callback via the messageReceived() + method. + + To open a pipe and wait for another client to connect to it, use the createPipe() + method. + + To act as a socket server and create connections for one or more client, see the + InterprocessConnectionServer class. + + @see InterprocessConnectionServer, Socket, NamedPipe */ -class JUCE_API PositionedGlyph +class JUCE_API InterprocessConnection : public Thread, + private MessageListener { public: - /** Returns the character the glyph represents. */ - juce_wchar getCharacter() const throw() { return character; } - /** Checks whether the glyph is actually empty. */ - bool isWhitespace() const throw() { return CharacterFunctions::isWhitespace (character); } + /** Creates a connection. - /** Returns the position of the glyph's left-hand edge. */ - float getLeft() const throw() { return x; } - /** Returns the position of the glyph's right-hand edge. */ - float getRight() const throw() { return x + w; } - /** Returns the y position of the glyph's baseline. */ - float getBaselineY() const throw() { return y; } - /** Returns the y position of the top of the glyph. */ - float getTop() const throw() { return y - font.getAscent(); } - /** Returns the y position of the bottom of the glyph. */ - float getBottom() const throw() { return y + font.getDescent(); } + Connections are created manually, connecting them with the connectToSocket() + or connectToPipe() methods, or they are created automatically by a InterprocessConnectionServer + when a client wants to connect. - /** Shifts the glyph's position by a relative amount. */ - void moveBy (const float deltaX, - const float deltaY) throw(); + @param callbacksOnMessageThread if true, callbacks to the connectionMade(), + connectionLost() and messageReceived() methods will + always be made using the message thread; if false, + these will be called immediately on the connection's + own thread. + @param magicMessageHeaderNumber a magic number to use in the header to check the + validity of the data blocks being sent and received. This + can be any number, but the sender and receiver must obviously + use matching values or they won't recognise each other. + */ + InterprocessConnection (const bool callbacksOnMessageThread = true, + const uint32 magicMessageHeaderNumber = 0xf2b49e2c); - /** Draws the glyph into a graphics context. */ - void draw (const Graphics& g) const throw(); + /** Destructor. */ + ~InterprocessConnection(); - /** Draws the glyph into a graphics context, with an extra transform applied to it. */ - void draw (const Graphics& g, const AffineTransform& transform) const throw(); + /** Tries to connect this object to a socket. - /** Returns the path for this glyph. + For this to work, the machine on the other end needs to have a InterprocessConnectionServer + object waiting to receive client connections on this port number. - @param path the glyph's outline will be appended to this path + @param hostName the host computer, either a network address or name + @param portNumber the socket port number to try to connect to + @param timeOutMillisecs how long to keep trying before giving up + @returns true if the connection is established successfully + @see Socket */ - void createPath (Path& path) const throw(); + bool connectToSocket (const String& hostName, + const int portNumber, + const int timeOutMillisecs); - /** Checks to see if a point lies within this glyph. */ - bool hitTest (float x, float y) const throw(); + /** Tries to connect the object to an existing named pipe. - juce_UseDebuggingNewOperator + For this to work, another process on the same computer must already have opened + an InterprocessConnection object and used createPipe() to create a pipe for this + to connect to. -private: + You can optionally specify a timeout length to be passed to the NamedPipe::read() method. - friend class GlyphArrangement; - float x, y, w; - Font font; - juce_wchar character; - int glyph; + @returns true if it connects successfully. + @see createPipe, NamedPipe + */ + bool connectToPipe (const String& pipeName, + const int pipeReceiveMessageTimeoutMs = -1); - PositionedGlyph() throw(); -}; + /** Tries to create a new pipe for other processes to connect to. -/** - A set of glyphs, each with a position. + This creates a pipe with the given name, so that other processes can use + connectToPipe() to connect to the other end. - You can create a GlyphArrangement, text to it and then draw it onto a - graphics context. It's used internally by the text methods in the - Graphics class, but can be used directly if more control is needed. + You can optionally specify a timeout length to be passed to the NamedPipe::read() method. - @see Font, PositionedGlyph -*/ -class JUCE_API GlyphArrangement -{ -public: + If another process is already using this pipe, this will fail and return false. + */ + bool createPipe (const String& pipeName, + const int pipeReceiveMessageTimeoutMs = -1); - /** Creates an empty arrangement. */ - GlyphArrangement() throw(); + /** Disconnects and closes any currently-open sockets or pipes. */ + void disconnect(); - /** Takes a copy of another arrangement. */ - GlyphArrangement (const GlyphArrangement& other) throw(); + /** True if a socket or pipe is currently active. */ + bool isConnected() const; - /** Copies another arrangement onto this one. + /** Returns the socket that this connection is using (or null if it uses a pipe). */ + StreamingSocket* getSocket() const throw() { return socket; } - To add another arrangement without clearing this one, use addGlyphArrangement(). - */ - const GlyphArrangement& operator= (const GlyphArrangement& other) throw(); + /** Returns the pipe that this connection is using (or null if it uses a socket). */ + NamedPipe* getPipe() const throw() { return pipe; } - /** Destructor. */ - ~GlyphArrangement() throw(); + /** Returns the name of the machine at the other end of this connection. - /** Returns the total number of glyphs in the arrangement. */ - int getNumGlyphs() const throw() { return glyphs.size(); } + This will return an empty string if the other machine isn't known for + some reason. + */ + const String getConnectedHostName() const; - /** Returns one of the glyphs from the arrangement. + /** Tries to send a message to the other end of this connection. - @param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be - careful not to pass an out-of-range index here, as it - doesn't do any bounds-checking. - */ - PositionedGlyph& getGlyph (const int index) const throw(); + This will fail if it's not connected, or if there's some kind of write error. If + it succeeds, the connection object at the other end will receive the message by + a callback to its messageReceived() method. - /** Clears all text from the arrangement and resets it. + @see messageReceived */ - void clear() throw(); - - /** Appends a line of text to the arrangement. + bool sendMessage (const MemoryBlock& message); - This will add the text as a single line, where x is the left-hand edge of the - first character, and y is the position for the text's baseline. + /** Called when the connection is first connected. - If the text contains new-lines or carriage-returns, this will ignore them - use - addJustifiedText() to add multi-line arrangements. + If the connection was created with the callbacksOnMessageThread flag set, then + this will be called on the message thread; otherwise it will be called on a server + thread. */ - void addLineOfText (const Font& font, - const String& text, - const float x, - const float y) throw(); + virtual void connectionMade() = 0; - /** Adds a line of text, truncating it if it's wider than a specified size. + /** Called when the connection is broken. - This is the same as addLineOfText(), but if the line's width exceeds the value - specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."), - if useEllipsis is true, or if this is false, it will just drop any subsequent characters. + If the connection was created with the callbacksOnMessageThread flag set, then + this will be called on the message thread; otherwise it will be called on a server + thread. */ - void addCurtailedLineOfText (const Font& font, - const String& text, - float x, - const float y, - const float maxWidthPixels, - const bool useEllipsis) throw(); + virtual void connectionLost() = 0; - /** Adds some multi-line text, breaking lines at word-boundaries if they are too wide. + /** Called when a message arrives. - This will add text to the arrangement, breaking it into new lines either where there - is a new-line or carriage-return character in the text, or where a line's width - exceeds the value set in maxLineWidth. + When the object at the other end of this connection sends us a message with sendMessage(), + this callback is used to deliver it to us. - Each line that is added will be laid out using the flags set in horizontalLayout, so - the lines can be left- or right-justified, or centred horizontally in the space - between x and (x + maxLineWidth). + If the connection was created with the callbacksOnMessageThread flag set, then + this will be called on the message thread; otherwise it will be called on a server + thread. - The y co-ordinate is the position of the baseline of the first line of text - subsequent - lines will be placed below it, separated by a distance of font.getHeight(). + @see sendMessage */ - void addJustifiedText (const Font& font, - const String& text, - float x, float y, - const float maxLineWidth, - const Justification& horizontalLayout) throw(); - - /** Tries to fit some text withing a given space. + virtual void messageReceived (const MemoryBlock& message) = 0; - This does its best to make the given text readable within the specified rectangle, - so it useful for labelling things. + juce_UseDebuggingNewOperator - If the text is too big, it'll be squashed horizontally or broken over multiple lines - if the maximumLinesToUse value allows this. If the text just won't fit into the space, - it'll cram as much as possible in there, and put some ellipsis at the end to show that - it's been truncated. +private: + CriticalSection pipeAndSocketLock; + StreamingSocket* socket; + NamedPipe* pipe; + bool callbackConnectionState; + const bool useMessageThread; + const uint32 magicMessageHeader; + int pipeReceiveMessageTimeout; - A Justification parameter lets you specify how the text is laid out within the rectangle, - both horizontally and vertically. + friend class InterprocessConnectionServer; - @see Graphics::drawFittedText - */ - void addFittedText (const Font& font, - const String& text, - const float x, const float y, - const float width, const float height, - const Justification& layout, - int maximumLinesToUse, - const float minimumHorizontalScale = 0.7f) throw(); + void initialiseWithSocket (StreamingSocket* const socket_); + void initialiseWithPipe (NamedPipe* const pipe_); - /** Appends another glyph arrangement to this one. */ - void addGlyphArrangement (const GlyphArrangement& other) throw(); + void handleMessage (const Message& message); - /** Draws this glyph arrangement to a graphics context. + void connectionMadeInt(); + void connectionLostInt(); + void deliverDataInt (const MemoryBlock& data); - This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&) - method, which renders the glyphs as filled vectors. - */ - void draw (const Graphics& g) const throw(); + bool readNextMessageInt(); + void run(); - /** Draws this glyph arrangement to a graphics context. + InterprocessConnection (const InterprocessConnection&); + const InterprocessConnection& operator= (const InterprocessConnection&); +}; - This renders the paths as filled vectors, so is far slower than the draw (Graphics&) - method for non-transformed arrangements. - */ - void draw (const Graphics& g, const AffineTransform& transform) const throw(); +#endif // __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__ +/********* End of inlined file: juce_InterprocessConnection.h *********/ - /** Converts the set of glyphs into a path. +#endif +#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ - @param path the glyphs' outlines will be appended to this path - */ - void createPath (Path& path) const throw(); +/********* Start of inlined file: juce_InterprocessConnectionServer.h *********/ +#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ +#define __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ - /** Looks for a glyph that contains the given co-ordinate. +/** + An object that waits for client sockets to connect to a port on this host, and + creates InterprocessConnection objects for each one. - @returns the index of the glyph, or -1 if none were found. - */ - int findGlyphIndexAt (float x, float y) const throw(); + To use this, create a class derived from it which implements the createConnectionObject() + method, so that it creates suitable connection objects for each client that tries + to connect. - /** Finds the smallest rectangle that will enclose a subset of the glyphs. + @see InterprocessConnection +*/ +class JUCE_API InterprocessConnectionServer : private Thread +{ +public: - @param startIndex the first glyph to test - @param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after - startIndex will be included - @param left on return, the leftmost co-ordinate of the rectangle - @param top on return, the top co-ordinate of the rectangle - @param right on return, the rightmost co-ordinate of the rectangle - @param bottom on return, the bottom co-ordinate of the rectangle - @param includeWhitespace if true, the extent of any whitespace characters will also - be taken into account + /** Creates an uninitialised server object. */ - void getBoundingBox (int startIndex, - int numGlyphs, - float& left, - float& top, - float& right, - float& bottom, - const bool includeWhitespace) const throw(); + InterprocessConnectionServer(); - /** Shifts a set of glyphs by a given amount. + /** Destructor. */ + ~InterprocessConnectionServer(); - @param startIndex the first glyph to transform - @param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after - startIndex will be used - @param deltaX the amount to add to their x-positions - @param deltaY the amount to add to their y-positions - */ - void moveRangeOfGlyphs (int startIndex, int numGlyphs, - const float deltaX, - const float deltaY) throw(); + /** Starts an internal thread which listens on the given port number. - /** Removes a set of glyphs from the arrangement. + While this is running, in another process tries to connect with the + InterprocessConnection::connectToSocket() method, this object will call + createConnectionObject() to create a connection to that client. - @param startIndex the first glyph to remove - @param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after - startIndex will be deleted + Use stop() to stop the thread running. + + @see createConnectionObject, stop */ - void removeRangeOfGlyphs (int startIndex, int numGlyphs) throw(); + bool beginWaitingForSocket (const int portNumber); - /** Expands or compresses a set of glyphs horizontally. + /** Terminates the listener thread, if it's active. - @param startIndex the first glyph to transform - @param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after - startIndex will be used - @param horizontalScaleFactor how much to scale their horizontal width by + @see beginWaitingForSocket */ - void stretchRangeOfGlyphs (int startIndex, int numGlyphs, - const float horizontalScaleFactor) throw(); + void stop(); - /** Justifies a set of glyphs within a given space. +protected: + /** Creates a suitable connection object for a client process that wants to + connect to this one. - This moves the glyphs as a block so that the whole thing is located within the - given rectangle with the specified layout. + This will be called by the listener thread when a client process tries + to connect, and must return a new InterprocessConnection object that will + then run as this end of the connection. - If the Justification::horizontallyJustified flag is specified, each line will - be stretched out to fill the specified width. + @see InterprocessConnection */ - void justifyGlyphs (const int startIndex, const int numGlyphs, - const float x, - const float y, - const float width, - const float height, - const Justification& justification) throw(); + virtual InterprocessConnection* createConnectionObject() = 0; + +public: juce_UseDebuggingNewOperator private: - OwnedArray glyphs; - - int insertEllipsis (const Font& font, const float maxXPos, const int startIndex, int endIndex) throw(); - int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, - const Justification& justification, float minimumHorizontalScale) throw(); - void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); -}; + StreamingSocket* volatile socket; -#endif // __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ -/********* End of inlined file: juce_GlyphArrangement.h *********/ + void run(); -#endif -#ifndef __JUCE_FILLTYPE_JUCEHEADER__ + InterprocessConnectionServer (const InterprocessConnectionServer&); + const InterprocessConnectionServer& operator= (const InterprocessConnectionServer&); +}; -#endif -#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ +#endif // __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__ +/********* End of inlined file: juce_InterprocessConnectionServer.h *********/ #endif -#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ +#ifndef __JUCE_MESSAGE_JUCEHEADER__ #endif -#ifndef __JUCE_EDGETABLE_JUCEHEADER__ +#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ #endif -#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ - -/********* Start of inlined file: juce_LowLevelGraphicsContext.h *********/ -#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ -#define __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ - -/********* Start of inlined file: juce_Image.h *********/ -#ifndef __JUCE_IMAGE_JUCEHEADER__ -#define __JUCE_IMAGE_JUCEHEADER__ - -/** - Holds a fixed-size bitmap. - - The image is stored in either 24-bit RGB or 32-bit premultiplied-ARGB format. +#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__ - To draw into an image, create a Graphics object for it. - e.g. @code +/********* Start of inlined file: juce_MessageManager.h *********/ +#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__ +#define __JUCE_MESSAGEMANAGER_JUCEHEADER__ - // create a transparent 500x500 image.. - Image myImage (Image::RGB, 500, 500, true); +class Component; +class MessageManagerLock; - Graphics g (myImage); - g.setColour (Colours::red); - g.fillEllipse (20, 20, 300, 200); // draws a red ellipse in our image. - @endcode +/** See MessageManager::callFunctionOnMessageThread() for use of this function type +*/ +typedef void* (MessageCallbackFunction) (void* userData); - Other useful ways to create an image are with the ImageCache class, or the - ImageFileFormat, which provides a way to load common image files. +/** Delivers Message objects to MessageListeners, and handles the event-dispatch loop. - @see Graphics, ImageFileFormat, ImageCache, ImageConvolutionKernel + @see Message, MessageListener, MessageManagerLock, JUCEApplication */ -class JUCE_API Image +class JUCE_API MessageManager { public: - enum PixelFormat - { - RGB, /**<< each pixel is a 3-byte packed RGB colour value. For byte order, see the PixelRGB class. */ - ARGB, /**<< each pixel is a 4-byte ARGB premultiplied colour value. For byte order, see the PixelARGB class. */ - SingleChannel /**<< each pixel is a 1-byte alpha channel value. */ - }; + /** Returns the global instance of the MessageManager. */ + static MessageManager* getInstance() throw(); - /** Creates an in-memory image with a specified size and format. + /** Runs the event dispatch loop until a stop message is posted. - To create an image that can use native OS rendering methods, see createNativeImage(). + This method is only intended to be run by the application's startup routine, + as it blocks, and will only return after the stopDispatchLoop() method has been used. - @param format the number of colour channels in the image - @param imageWidth the desired width of the image, in pixels - this value must be - greater than zero (otherwise a width of 1 will be used) - @param imageHeight the desired width of the image, in pixels - this value must be - greater than zero (otherwise a height of 1 will be used) - @param clearImage if true, the image will initially be cleared to black or transparent - black. If false, the image may contain random data, and the - user will have to deal with this + @see stopDispatchLoop */ - Image (const PixelFormat format, - const int imageWidth, - const int imageHeight, - const bool clearImage); + void runDispatchLoop(); - /** Creates a copy of another image. + /** Sends a signal that the dispatch loop should terminate. - @see createCopy + After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods + will be interrupted and will return. + + @see runDispatchLoop */ - Image (const Image& other); + void stopDispatchLoop(); - /** Destructor. */ - virtual ~Image(); + /** Returns true if the stopDispatchLoop() method has been called. + */ + bool hasStopMessageBeenSent() const throw() { return quitMessagePosted; } - /** Tries to create an image that is uses native drawing methods when you render - onto it. + /** Synchronously dispatches messages until a given time has elapsed. - On some platforms this will just return a normal software-based image. + Returns false if a quit message has been posted by a call to stopDispatchLoop(), + otherwise returns true. */ - static Image* createNativeImage (const PixelFormat format, - const int imageWidth, - const int imageHeight, - const bool clearImage); + bool runDispatchLoopUntil (int millisecondsToRunFor); - /** Returns the image's width (in pixels). */ - int getWidth() const throw() { return imageWidth; } + /** Calls a function using the message-thread. - /** Returns the image's height (in pixels). */ - int getHeight() const throw() { return imageHeight; } + This can be used by any thread to cause this function to be called-back + by the message thread. If it's the message-thread that's calling this method, + then the function will just be called; if another thread is calling, a message + will be posted to the queue, and this method will block until that message + is delivered, the function is called, and the result is returned. - /** Returns a rectangle with the same size as this image. - The rectangle is always at position (0, 0). - */ - const Rectangle getBounds() const throw() { return Rectangle (0, 0, imageWidth, imageHeight); } + Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller + thread has a critical section locked, which an unrelated message callback then tries to lock + before the message thread gets round to processing this callback. - /** Returns the image's pixel format. */ - PixelFormat getFormat() const throw() { return format; } + @param callback the function to call - its signature must be @code + void* myCallbackFunction (void*) @endcode + @param userData a user-defined pointer that will be passed to the function that gets called + @returns the value that the callback function returns. + @see MessageManagerLock + */ + void* callFunctionOnMessageThread (MessageCallbackFunction* callback, + void* userData); - /** True if the image's format is ARGB. */ - bool isARGB() const throw() { return format == ARGB; } + /** Returns true if the caller-thread is the message thread. */ + bool isThisTheMessageThread() const throw(); - /** True if the image's format is RGB. */ - bool isRGB() const throw() { return format == RGB; } + /** Called to tell the manager which thread is the one that's running the dispatch loop. - /** True if the image contains an alpha-channel. */ - bool hasAlphaChannel() const throw() { return format != RGB; } + (Best to ignore this method unless you really know what you're doing..) + @see getCurrentMessageThread + */ + void setCurrentMessageThread (const Thread::ThreadID threadId) throw(); - /** Clears a section of the image with a given colour. + /** Returns the ID of the current message thread, as set by setCurrentMessageThread(). - This won't do any alpha-blending - it just sets all pixels in the image to - the given colour (which may be non-opaque if the image has an alpha channel). + (Best to ignore this method unless you really know what you're doing..) + @see setCurrentMessageThread */ - virtual void clear (int x, int y, int w, int h, - const Colour& colourToClearTo = Colour (0x00000000)); + Thread::ThreadID getCurrentMessageThread() const throw() { return messageThreadId; } - /** Returns a new image that's a copy of this one. + /** Returns true if the caller thread has currenltly got the message manager locked. - A new size for the copied image can be specified, or values less than - zero can be passed-in to use the image's existing dimensions. + see the MessageManagerLock class for more info about this. - It's up to the caller to delete the image when no longer needed. + This will be true if the caller is the message thread, because that automatically + gains a lock while a message is being dispatched. */ - virtual Image* createCopy (int newWidth = -1, - int newHeight = -1, - const Graphics::ResamplingQuality quality = Graphics::mediumResamplingQuality) const; + bool currentThreadHasLockedMessageManager() const throw(); - /** Returns a new single-channel image which is a copy of the alpha-channel of this image. - */ - virtual Image* createCopyOfAlphaChannel() const; + /** Sends a message to all other JUCE applications that are running. - /** Returns the colour of one of the pixels in the image. + @param messageText the string that will be passed to the actionListenerCallback() + method of the broadcast listeners in the other app. + @see registerBroadcastListener, ActionListener + */ + static void broadcastMessage (const String& messageText) throw(); - If the co-ordinates given are beyond the image's boundaries, this will - return Colours::transparentBlack. + /** Registers a listener to get told about broadcast messages. - (0, 0) is the image's top-left corner. + The actionListenerCallback() callback's string parameter + is the message passed into broadcastMessage(). - @see getAlphaAt, setPixelAt, blendPixelAt + @see broadcastMessage */ - virtual const Colour getPixelAt (const int x, const int y) const; + void registerBroadcastListener (ActionListener* listener) throw(); - /** Sets the colour of one of the image's pixels. + /** Deregisters a broadcast listener. */ + void deregisterBroadcastListener (ActionListener* listener) throw(); - If the co-ordinates are beyond the image's boundaries, then nothing will - happen. + /** @internal */ + void deliverMessage (void*); + /** @internal */ + void deliverBroadcastMessage (const String&); + /** @internal */ + ~MessageManager() throw(); - Note that unlike blendPixelAt(), this won't do any alpha-blending, it'll - just replace the existing pixel with the given one. The colour's opacity - will be ignored if this image doesn't have an alpha-channel. + juce_UseDebuggingNewOperator - (0, 0) is the image's top-left corner. +private: + MessageManager() throw(); - @see blendPixelAt - */ - virtual void setPixelAt (const int x, const int y, const Colour& colour); + friend class MessageListener; + friend class ChangeBroadcaster; + friend class ActionBroadcaster; + friend class CallbackMessage; + static MessageManager* instance; - /** Changes the opacity of a pixel. + SortedSet messageListeners; + ActionListenerList* broadcastListeners; - This only has an effect if the image has an alpha channel and if the - given co-ordinates are inside the image's boundary. + friend class JUCEApplication; + bool quitMessagePosted, quitMessageReceived; + Thread::ThreadID messageThreadId; - The multiplier must be in the range 0 to 1.0, and the current alpha - at the given co-ordinates will be multiplied by this value. + VoidArray modalComponents; + static void* exitModalLoopCallback (void*); - @see getAlphaAt, setPixelAt - */ - virtual void multiplyAlphaAt (const int x, const int y, const float multiplier); + void postMessageToQueue (Message* const message); + void postCallbackMessage (Message* const message); - /** Changes the overall opacity of the image. + static void doPlatformSpecificInitialisation(); + static void doPlatformSpecificShutdown(); - This will multiply the alpha value of each pixel in the image by the given - amount (limiting the resulting alpha values between 0 and 255). This allows - you to make an image more or less transparent. + friend class MessageManagerLock; + Thread::ThreadID volatile threadWithLock; + CriticalSection lockingLock; - If the image doesn't have an alpha channel, this won't have any effect. - */ - virtual void multiplyAllAlphas (const float amountToMultiplyBy); + MessageManager (const MessageManager&); + const MessageManager& operator= (const MessageManager&); +}; - /** Changes all the colours to be shades of grey, based on their current luminosity. - */ - virtual void desaturate(); +/** Used to make sure that the calling thread has exclusive access to the message loop. - /** Retrieves a section of an image as raw pixel data, so it can be read or written to. + Because it's not thread-safe to call any of the Component or other UI classes + from threads other than the message thread, one of these objects can be used to + lock the message loop and allow this to be done. The message thread will be + suspended for the lifetime of the MessageManagerLock object, so create one on + the stack like this: @code + void MyThread::run() + { + someData = 1234; - You should only use this class as a last resort - messing about with the internals of - an image is only recommended for people who really know what they're doing! + const MessageManagerLock mmLock; + // the event loop will now be locked so it's safe to make a few calls.. - A BitmapData object should be used as a temporary, stack-based object. Don't keep one - hanging around while the image is being used elsewhere. + myComponent->setBounds (newBounds); + myComponent->repaint(); - Depending on the way the image class is implemented, this may create a temporary buffer - which is copied back to the image when the object is deleted, or it may just get a pointer - directly into the image's raw data. + // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope + } + @endcode - You can use the stride and data values in this class directly, but don't alter them! - The actual format of the pixel data depends on the image's format - see Image::getFormat(), - and the PixelRGB, PixelARGB and PixelAlpha classes for more info. - */ - class BitmapData - { - public: - BitmapData (Image& image, int x, int y, int w, int h, const bool needsToBeWritable) throw(); - BitmapData (const Image& image, int x, int y, int w, int h) throw(); - ~BitmapData() throw(); + Obviously be careful not to create one of these and leave it lying around, or + your app will grind to a halt! - /** Returns a pointer to the start of a line in the image. - The co-ordinate you provide here isn't checked, so it's the caller's responsibility to make - sure it's not out-of-range. - */ - inline uint8* getLinePointer (const int y) const throw() { return data + y * lineStride; } + Another caveat is that using this in conjunction with other CriticalSections + can create lots of interesting ways of producing a deadlock! In particular, if + your message thread calls stopThread() for a thread that uses these locks, + you'll get an (occasional) deadlock.. - /** Returns a pointer to a pixel in the image. - The co-ordinates you give here are not checked, so it's the caller's responsibility to make sure they're - not out-of-range. - */ - inline uint8* getPixelPointer (const int x, const int y) const throw() { return data + y * lineStride + x * pixelStride; } + @see MessageManager, MessageManager::currentThreadHasLockedMessageManager +*/ +class JUCE_API MessageManagerLock +{ +public: - uint8* data; - int lineStride, pixelStride, width, height; + /** Tries to acquire a lock on the message manager. - private: - BitmapData (const BitmapData&); - const BitmapData& operator= (const BitmapData&); - }; + The constructor attempts to gain a lock on the message loop, and the lock will be + kept for the lifetime of this object. - /** Copies some pixel values to a rectangle of the image. + Optionally, you can pass a thread object here, and while waiting to obtain the lock, + this method will keep checking whether the thread has been given the + Thread::signalThreadShouldExit() signal. If this happens, then it will return + without gaining the lock. If you pass a thread, you must check whether the lock was + successful by calling lockWasGained(). If this is false, your thread is being told to + die, so you should take evasive action. - The format of the pixel data must match that of the image itself, and the - rectangle supplied must be within the image's bounds. - */ - virtual void setPixelData (int destX, int destY, int destW, int destH, - const uint8* sourcePixelData, int sourceLineStride); + If you pass zero for the thread object, it will wait indefinitely for the lock - be + careful when doing this, because it's very easy to deadlock if your message thread + attempts to call stopThread() on a thread just as that thread attempts to get the + message lock. - /** Copies a section of the image to somewhere else within itself. - */ - virtual void moveImageSection (int destX, int destY, - int sourceX, int sourceY, - int width, int height); + If the calling thread already has the lock, nothing will be done, so it's safe and + quick to use these locks recursively. - /** Creates a RectangleList containing rectangles for all non-transparent pixels - of the image. + E.g. + @code + void run() + { + ... - @param result the list that will have the area added to it - @param alphaThreshold for a semi-transparent image, any pixels whose alpha is - above this level will be considered opaque - */ - void createSolidAreaMask (RectangleList& result, - const float alphaThreshold = 0.5f) const; + while (! threadShouldExit()) + { + MessageManagerLock mml (Thread::getCurrentThread()); - juce_UseDebuggingNewOperator + if (! mml.lockWasGained()) + return; // another thread is trying to kill us! - /** Creates a context suitable for drawing onto this image. + ..do some locked stuff here.. + } + + ..and now the MM is now unlocked.. + } + @endcode - Don't call this method directly! It's used internally by the Graphics class. */ - virtual LowLevelGraphicsContext* createLowLevelContext(); + MessageManagerLock (Thread* const threadToCheckForExitSignal = 0) throw(); -protected: - friend class BitmapData; - const PixelFormat format; - const int imageWidth, imageHeight; + /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob + instead of a thread. - /** Used internally so that subclasses can call a constructor that doesn't allocate memory */ - Image (const PixelFormat format, - const int imageWidth, - const int imageHeight); + See the MessageManagerLock (Thread*) constructor for details on how this works. + */ + MessageManagerLock (ThreadPoolJob* const jobToCheckForExitSignal) throw(); - int pixelStride, lineStride; - uint8* imageData; + /** Releases the current thread's lock on the message manager. + + Make sure this object is created and deleted by the same thread, + otherwise there are no guarantees what will happen! + */ + ~MessageManagerLock() throw(); + + /** Returns true if the lock was successfully acquired. + + (See the constructor that takes a Thread for more info). + */ + bool lockWasGained() const throw() { return locked; } private: + bool locked, needsUnlocking; + void* sharedEvents; - const Image& operator= (const Image&); + void init (Thread* const thread, ThreadPoolJob* const job) throw(); + + MessageManagerLock (const MessageManagerLock&); + const MessageManagerLock& operator= (const MessageManagerLock&); }; -#endif // __JUCE_IMAGE_JUCEHEADER__ -/********* End of inlined file: juce_Image.h *********/ +#endif // __JUCE_MESSAGEMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_MessageManager.h *********/ + +#endif +#ifndef __JUCE_MULTITIMER_JUCEHEADER__ + +/********* Start of inlined file: juce_MultiTimer.h *********/ +#ifndef __JUCE_MULTITIMER_JUCEHEADER__ +#define __JUCE_MULTITIMER_JUCEHEADER__ /** - Interface class for graphics context objects, used internally by the Graphics class. + A type of timer class that can run multiple timers with different frequencies, + all of which share a single callback. - Users are not supposed to create instances of this class directly - do your drawing - via the Graphics object instead. + This class is very similar to the Timer class, but allows you run multiple + separate timers, where each one has a unique ID number. The methods in this + class are exactly equivalent to those in Timer, but with the addition of + this ID number. - It's a base class for different types of graphics context, that may perform software-based - or OS-accelerated rendering. + To use it, you need to create a subclass of MultiTimer, implementing the + timerCallback() method. Then you can start timers with startTimer(), and + each time the callback is triggered, it passes in the ID of the timer that + caused it. - E.g. the LowLevelGraphicsSoftwareRenderer renders onto an image in memory, but other - subclasses could render directly to a windows HDC, a Quartz context, or an OpenGL - context. + @see Timer */ -class JUCE_API LowLevelGraphicsContext +class JUCE_API MultiTimer { protected: - LowLevelGraphicsContext(); + /** Creates a MultiTimer. + + When created, no timers are running, so use startTimer() to start things off. + */ + MultiTimer() throw(); + + /** Creates a copy of another timer. + + Note that this timer will not contain any running timers, even if the one you're + copying from was running. + */ + MultiTimer (const MultiTimer& other) throw(); public: - virtual ~LowLevelGraphicsContext(); - /** Returns true if this device is vector-based, e.g. a printer. */ - virtual bool isVectorDevice() const = 0; + /** Destructor. */ + virtual ~MultiTimer(); - /** Moves the origin to a new position. + /** The user-defined callback routine that actually gets called by each of the + timers that are running. - The co-ords are relative to the current origin, and indicate the new position - of (0, 0). + It's perfectly ok to call startTimer() or stopTimer() from within this + callback to change the subsequent intervals. */ - virtual void setOrigin (int x, int y) = 0; + virtual void timerCallback (const int timerId) = 0; - virtual bool clipToRectangle (const Rectangle& r) = 0; - virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; - virtual void excludeClipRectangle (const Rectangle& r) = 0; - virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0; - virtual void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) = 0; + /** Starts a timer and sets the length of interval required. - virtual bool clipRegionIntersects (const Rectangle& r) = 0; - virtual const Rectangle getClipBounds() const = 0; - virtual bool isClipEmpty() const = 0; + If the timer is already started, this will reset it, so the + time between calling this method and the next timer callback + will not be less than the interval length passed in. - virtual void saveState() = 0; - virtual void restoreState() = 0; + @param timerId a unique Id number that identifies the timer to + start. This is the id that will be passed back + to the timerCallback() method when this timer is + triggered + @param intervalInMilliseconds the interval to use (any values less than 1 will be + rounded up to 1) + */ + void startTimer (const int timerId, const int intervalInMilliseconds) throw(); - virtual void setFill (const FillType& fillType) = 0; - virtual void setOpacity (float newOpacity) = 0; - virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0; + /** Stops a timer. - virtual void fillRect (const Rectangle& r, const bool replaceExistingContents) = 0; - virtual void fillPath (const Path& path, const AffineTransform& transform) = 0; + If a timer has been started with the given ID number, it will be cancelled. + No more callbacks will be made for the specified timer after this method returns. - virtual void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, const bool fillEntireClipAsTiles) = 0; + If this is called from a different thread, any callbacks that may + be currently executing may be allowed to finish before the method + returns. + */ + void stopTimer (const int timerId) throw(); - virtual void drawLine (double x1, double y1, double x2, double y2) = 0; - virtual void drawVerticalLine (const int x, double top, double bottom) = 0; - virtual void drawHorizontalLine (const int y, double left, double right) = 0; + /** Checks whether a timer has been started for a specified ID. - virtual void setFont (const Font& newFont) = 0; - virtual const Font getFont() = 0; - virtual void drawGlyph (int glyphNumber, const AffineTransform& transform) = 0; + @returns true if a timer with the given ID is running. + */ + bool isTimerRunning (const int timerId) const throw(); + + /** Returns the interval for a specified timer ID. + + @returns the timer's interval in milliseconds if it's running, or 0 if it's no timer + is running for the ID number specified. + */ + int getTimerInterval (const int timerId) const throw(); + +private: + CriticalSection timerListLock; + VoidArray timers; + + const MultiTimer& operator= (const MultiTimer&); }; -#endif // __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ -/********* End of inlined file: juce_LowLevelGraphicsContext.h *********/ +#endif // __JUCE_MULTITIMER_JUCEHEADER__ +/********* End of inlined file: juce_MultiTimer.h *********/ #endif -#ifndef __JUCE_GRAPHICS_JUCEHEADER__ +#ifndef __JUCE_TIMER_JUCEHEADER__ #endif -#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ +#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ -/********* Start of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h *********/ -#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ -#define __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ +/********* Start of inlined file: juce_ArrowButton.h *********/ +#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ +#define __JUCE_ARROWBUTTON_JUCEHEADER__ -class LLGCSavedState; +/********* Start of inlined file: juce_DropShadowEffect.h *********/ +#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ +#define __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ /** - A lowest-common-denominator implementation of LowLevelGraphicsContext that does all - its rendering in memory. + An effect filter that adds a drop-shadow behind the image's content. - User code is not supposed to create instances of this class directly - do all your - rendering via the Graphics class instead. + (This will only work on images/components that aren't opaque, of course). + + When added to a component, this effect will draw a soft-edged + shadow based on what gets drawn inside it. The shadow will also + be applied to the component's children. + + For speed, this doesn't use a proper gaussian blur, but cheats by + using a simple bilinear filter. If you need a really high-quality + shadow, check out ImageConvolutionKernel::createGaussianBlur() + + @see Component::setComponentEffect */ -class JUCE_API LowLevelGraphicsSoftwareRenderer : public LowLevelGraphicsContext +class JUCE_API DropShadowEffect : public ImageEffectFilter { public: - LowLevelGraphicsSoftwareRenderer (Image& imageToRenderOn); - ~LowLevelGraphicsSoftwareRenderer(); + /** Creates a default drop-shadow effect. - bool isVectorDevice() const; + To customise the shadow's appearance, use the setShadowProperties() + method. + */ + DropShadowEffect(); - void setOrigin (int x, int y); + /** Destructor. */ + ~DropShadowEffect(); - bool clipToRectangle (const Rectangle& r); - bool clipToRectangleList (const RectangleList& clipRegion); - void excludeClipRectangle (const Rectangle& r); - void clipToPath (const Path& path, const AffineTransform& transform); - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); + /** Sets up parameters affecting the shadow's appearance. - bool clipRegionIntersects (const Rectangle& r); - const Rectangle getClipBounds() const; - bool isClipEmpty() const; + @param newRadius the (approximate) radius of the blur used + @param newOpacity the opacity with which the shadow is rendered + @param newShadowOffsetX allows the shadow to be shifted in relation to the + component's contents + @param newShadowOffsetY allows the shadow to be shifted in relation to the + component's contents + */ + void setShadowProperties (const float newRadius, + const float newOpacity, + const int newShadowOffsetX, + const int newShadowOffsetY); - void saveState(); - void restoreState(); + /** @internal */ + void applyEffect (Image& sourceImage, Graphics& destContext); - void setFill (const FillType& fillType); - void setOpacity (float opacity); - void setInterpolationQuality (Graphics::ResamplingQuality quality); + juce_UseDebuggingNewOperator - void fillRect (const Rectangle& r, const bool replaceExistingContents); - void fillPath (const Path& path, const AffineTransform& transform); +private: + int offsetX, offsetY; + float radius, opacity; +}; - void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, const bool fillEntireClipAsTiles); +#endif // __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ +/********* End of inlined file: juce_DropShadowEffect.h *********/ - void drawLine (double x1, double y1, double x2, double y2); +/** + A button with an arrow in it. - void drawVerticalLine (const int x, double top, double bottom); - void drawHorizontalLine (const int x, double top, double bottom); + @see Button +*/ +class JUCE_API ArrowButton : public Button +{ +public: - void setFont (const Font& newFont); - const Font getFont(); - void drawGlyph (int glyphNumber, float x, float y); - void drawGlyph (int glyphNumber, const AffineTransform& transform); + /** Creates an ArrowButton. + + @param buttonName the name to give the button + @param arrowDirection the direction the arrow should point in, where 0.0 is + pointing right, 0.25 is down, 0.5 is left, 0.75 is up + @param arrowColour the colour to use for the arrow + */ + ArrowButton (const String& buttonName, + float arrowDirection, + const Colour& arrowColour); + + /** Destructor. */ + ~ArrowButton(); juce_UseDebuggingNewOperator protected: + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); - Image& image; + /** @internal */ + void buttonStateChanged(); - LLGCSavedState* currentState; - OwnedArray stateStack; +private: - LowLevelGraphicsSoftwareRenderer (const LowLevelGraphicsSoftwareRenderer& other); - const LowLevelGraphicsSoftwareRenderer& operator= (const LowLevelGraphicsSoftwareRenderer&); + Colour colour; + DropShadowEffect shadow; + Path path; + int offset; + + ArrowButton (const ArrowButton&); + const ArrowButton& operator= (const ArrowButton&); }; -#endif // __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ -/********* End of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h *********/ +#endif // __JUCE_ARROWBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_ArrowButton.h *********/ #endif -#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ +#ifndef __JUCE_BUTTON_JUCEHEADER__ -/********* Start of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h *********/ -#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ -#define __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ +#endif +#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ + +/********* Start of inlined file: juce_DrawableButton.h *********/ +#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ +#define __JUCE_DRAWABLEBUTTON_JUCEHEADER__ + +/********* Start of inlined file: juce_Drawable.h *********/ +#ifndef __JUCE_DRAWABLE_JUCEHEADER__ +#define __JUCE_DRAWABLE_JUCEHEADER__ /** - An implementation of LowLevelGraphicsContext that turns the drawing operations - into a PostScript document. + The base class for objects which can draw themselves, e.g. polygons, images, etc. + @see DrawableComposite, DrawableImage, DrawablePath, DrawableText */ -class JUCE_API LowLevelGraphicsPostScriptRenderer : public LowLevelGraphicsContext +class JUCE_API Drawable { -public: - - LowLevelGraphicsPostScriptRenderer (OutputStream& resultingPostScript, - const String& documentTitle, - const int totalWidth, - const int totalHeight); - - ~LowLevelGraphicsPostScriptRenderer(); - - bool isVectorDevice() const; - void setOrigin (int x, int y); +protected: - bool clipToRectangle (const Rectangle& r); - bool clipToRectangleList (const RectangleList& clipRegion); - void excludeClipRectangle (const Rectangle& r); - void clipToPath (const Path& path, const AffineTransform& transform); - void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); + /** The base class can't be instantiated directly. - void saveState(); - void restoreState(); + @see DrawableComposite, DrawableImage, DrawablePath, DrawableText + */ + Drawable(); - bool clipRegionIntersects (const Rectangle& r); - const Rectangle getClipBounds() const; - bool isClipEmpty() const; +public: + /** Destructor. */ + virtual ~Drawable(); - void setFill (const FillType& fillType); - void setOpacity (float opacity); - void setInterpolationQuality (Graphics::ResamplingQuality quality); + /** Creates a deep copy of this Drawable object. - void fillRect (const Rectangle& r, const bool replaceExistingContents); - void fillPath (const Path& path, const AffineTransform& transform); + Use this to create a new copy of this and any sub-objects in the tree. + */ + virtual Drawable* createCopy() const = 0; - void drawImage (const Image& sourceImage, const Rectangle& srcClip, - const AffineTransform& transform, const bool fillEntireClipAsTiles); + /** Renders this Drawable object. + @see drawWithin + */ + void draw (Graphics& g, const float opacity, + const AffineTransform& transform = AffineTransform::identity) const; - void drawLine (double x1, double y1, double x2, double y2); + /** Renders the Drawable at a given offset within the Graphics context. - void drawVerticalLine (const int x, double top, double bottom); - void drawHorizontalLine (const int x, double top, double bottom); + The co-ordinates passed-in are used to translate the object relative to its own + origin before drawing it - this is basically a quick way of saying: - const Font getFont(); - void setFont (const Font& newFont); - void drawGlyph (int glyphNumber, const AffineTransform& transform); + @code + draw (g, AffineTransform::translation (x, y)). + @endcode + */ + void drawAt (Graphics& g, + const float x, + const float y, + const float opacity) const; - juce_UseDebuggingNewOperator + /** Renders the Drawable within a rectangle, scaling it to fit neatly inside without + changing its aspect-ratio. -protected: + The object can placed arbitrarily within the rectangle based on a Justification type, + and can either be made as big as possible, or just reduced to fit. - OutputStream& out; - int totalWidth, totalHeight; - bool needToClip; - Colour lastColour; + @param g the graphics context to render onto + @param destX top-left of the target rectangle to fit it into + @param destY top-left of the target rectangle to fit it into + @param destWidth size of the target rectangle to fit the image into + @param destHeight size of the target rectangle to fit the image into + @param placement defines the alignment and rescaling to use to fit + this object within the target rectangle. + @param opacity the opacity to use, in the range 0 to 1.0 + */ + void drawWithin (Graphics& g, + const int destX, + const int destY, + const int destWidth, + const int destHeight, + const RectanglePlacement& placement, + const float opacity) const; - struct SavedState + /** Holds the information needed when telling a drawable to render itself. + @see Drawable::draw + */ + class RenderingContext { - SavedState(); - ~SavedState(); + public: + RenderingContext (Graphics& g, const AffineTransform& transform, const float opacity) throw(); - RectangleList clip; - int xOffset, yOffset; - FillType fillType; - Font font; + Graphics& g; + AffineTransform transform; + float opacity; private: - const SavedState& operator= (const SavedState&); + const RenderingContext& operator= (const RenderingContext&); }; - OwnedArray stateStack; + /** Renders this Drawable object. + @see draw + */ + virtual void render (const RenderingContext& context) const = 0; - void writeClip(); - void writeColour (const Colour& colour); - void writePath (const Path& path) const; - void writeXY (const float x, const float y) const; - void writeTransform (const AffineTransform& trans) const; - void writeImage (const Image& im, const int sx, const int sy, const int maxW, const int maxH) const; + /** Returns the smallest rectangle that can contain this Drawable object. - LowLevelGraphicsPostScriptRenderer (const LowLevelGraphicsPostScriptRenderer& other); - const LowLevelGraphicsPostScriptRenderer& operator= (const LowLevelGraphicsPostScriptRenderer&); -}; + Co-ordinates are relative to the object's own origin. + */ + virtual void getBounds (float& x, float& y, float& width, float& height) const = 0; -#endif // __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ -/********* End of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h *********/ + /** Returns true if the given point is somewhere inside this Drawable. -#endif -#ifndef __JUCE_PATH_JUCEHEADER__ + Co-ordinates are relative to the object's own origin. + */ + virtual bool hitTest (float x, float y) const = 0; -#endif -#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ + /** Returns the name given to this drawable. + @see setName + */ + const String& getName() const throw() { return name; } -#endif -#ifndef __JUCE_LINE_JUCEHEADER__ + /** Assigns a name to this drawable. */ + void setName (const String& newName) throw() { name = newName; } -#endif -#ifndef __JUCE_POINT_JUCEHEADER__ + /** Tries to turn some kind of image file into a drawable. -#endif -#ifndef __JUCE_RECTANGLE_JUCEHEADER__ + The data could be an image that the ImageFileFormat class understands, or it + could be SVG. + */ + static Drawable* createFromImageData (const void* data, const int numBytes); -#endif -#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ + /** Tries to turn a stream containing some kind of image data into a drawable. -#endif -#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ + The data could be an image that the ImageFileFormat class understands, or it + could be SVG. + */ + static Drawable* createFromImageDataStream (InputStream& dataSource); -/********* Start of inlined file: juce_PositionedRectangle.h *********/ -#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ -#define __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ + /** Tries to turn a file containing some kind of image data into a drawable. -/** - A rectangle whose co-ordinates can be defined in terms of absolute or - proportional distances. + The data could be an image that the ImageFileFormat class understands, or it + could be SVG. + */ + static Drawable* createFromImageFile (const File& file); - Designed mainly for storing component positions, this gives you a lot of - control over how each co-ordinate is stored, either as an absolute position, - or as a proportion of the size of a parent rectangle. + /** Attempts to parse an SVG (Scalable Vector Graphics) document, and to turn this + into a Drawable tree. - It also allows you to define the anchor points by which the rectangle is - positioned, so for example you could specify that the top right of the - rectangle should be an absolute distance from its parent's bottom-right corner. + The object returned must be deleted by the caller. If something goes wrong + while parsing, it may return 0. - This object can be stored as a string, which takes the form "x y w h", including - symbols like '%' and letters to indicate the anchor point. See its toString() - method for more info. + SVG is a pretty large and complex spec, and this doesn't aim to be a full + implementation, but it can return the basic vector objects. + */ + static Drawable* createFromSVG (const XmlElement& svgDocument); - Example usage: - @code - class MyComponent - { - void resized() - { - // this will set the child component's x to be 20% of our width, its y - // to be 30, its width to be 150, and its height to be 50% of our - // height.. - const PositionedRectangle pos1 ("20% 30 150 50%"); - pos1.applyToComponent (*myChildComponent1); - - // this will inset the child component with a gap of 10 pixels - // around each of its edges.. - const PositionedRectangle pos2 ("10 10 20M 20M"); - pos2.applyToComponent (*myChildComponent2); - } - }; - @endcode -*/ -class JUCE_API PositionedRectangle -{ -public: - - /** Creates an empty rectangle with all co-ordinates set to zero. - - The default anchor point is top-left; the default - */ - PositionedRectangle() throw(); - - /** Initialises a PositionedRectangle from a saved string version. - - The string must be in the format generated by toString(). - */ - PositionedRectangle (const String& stringVersion) throw(); - - /** Creates a copy of another PositionedRectangle. */ - PositionedRectangle (const PositionedRectangle& other) throw(); - - /** Copies another PositionedRectangle. */ - const PositionedRectangle& operator= (const PositionedRectangle& other) throw(); - - /** Destructor. */ - ~PositionedRectangle() throw(); - - /** Returns a string version of this position, from which it can later be - re-generated. - - The format is four co-ordinates, "x y w h". - - - If a co-ordinate is absolute, it is stored as an integer, e.g. "100". - - If a co-ordinate is proportional to its parent's width or height, it is stored - as a percentage, e.g. "80%". - - If the X or Y co-ordinate is relative to the parent's right or bottom edge, the - number has "R" appended to it, e.g. "100R" means a distance of 100 pixels from - the parent's right-hand edge. - - If the X or Y co-ordinate is relative to the parent's centre, the number has "C" - appended to it, e.g. "-50C" would be 50 pixels left of the parent's centre. - - If the X or Y co-ordinate should be anchored at the component's right or bottom - edge, then it has "r" appended to it. So "-50Rr" would mean that this component's - right-hand edge should be 50 pixels left of the parent's right-hand edge. - - If the X or Y co-ordinate should be anchored at the component's centre, then it - has "c" appended to it. So "-50Rc" would mean that this component's - centre should be 50 pixels left of the parent's right-hand edge. "40%c" means that - this component's centre should be placed 40% across the parent's width. - - If it's a width or height that should use the parentSizeMinusAbsolute mode, then - the number has "M" appended to it. - - To reload a stored string, use the constructor that takes a string parameter. - */ - const String toString() const throw(); - - /** Calculates the absolute position, given the size of the space that - it should go in. - - This will work out any proportional distances and sizes relative to the - target rectangle, and will return the absolute position. - - @see applyToComponent - */ - const Rectangle getRectangle (const Rectangle& targetSpaceToBeRelativeTo) const throw(); - - /** Same as getRectangle(), but returning the values as doubles rather than ints. + /** Tries to create a Drawable from a previously-saved ValueTree. + The ValueTree must have been created by the createValueTree() method. */ - void getRectangleDouble (const Rectangle& targetSpaceToBeRelativeTo, - double& x, - double& y, - double& width, - double& height) const throw(); - - /** This sets the bounds of the given component to this position. - - This is equivalent to writing: - @code - comp.setBounds (getRectangle (Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight()))); - @endcode + static Drawable* createFromValueTree (const ValueTree& tree) throw(); - @see getRectangle, updateFromComponent + /** Creates a ValueTree to represent this Drawable. + The VarTree that is returned can be turned back into a Drawable with + createFromValueTree(). */ - void applyToComponent (Component& comp) const throw(); - - /** Updates this object's co-ordinates to match the given rectangle. - - This will set all co-ordinates based on the given rectangle, re-calculating - any proportional distances, and using the current anchor points. - - So for example if the x co-ordinate mode is currently proportional, this will - re-calculate x based on the rectangle's relative position within the target - rectangle's width. + virtual ValueTree createValueTree() const throw() = 0; - If the target rectangle's width or height are zero then it may not be possible - to re-calculate some proportional co-ordinates. In this case, those co-ordinates - will not be changed. - */ - void updateFrom (const Rectangle& newPosition, - const Rectangle& targetSpaceToBeRelativeTo) throw(); + juce_UseDebuggingNewOperator - /** Same functionality as updateFrom(), but taking doubles instead of ints. - */ - void updateFromDouble (const double x, const double y, - const double width, const double height, - const Rectangle& targetSpaceToBeRelativeTo) throw(); +private: + Drawable (const Drawable&); + const Drawable& operator= (const Drawable&); - /** Updates this object's co-ordinates to match the bounds of this component. + String name; +}; - This is equivalent to calling updateFrom() with the component's bounds and - it parent size. +#endif // __JUCE_DRAWABLE_JUCEHEADER__ +/********* End of inlined file: juce_Drawable.h *********/ - If the component doesn't currently have a parent, then proportional co-ordinates - might not be updated because it would need to know the parent's size to do the - maths for this. - */ - void updateFromComponent (const Component& comp) throw(); +/** + A button that displays a Drawable. - /** Specifies the point within the rectangle, relative to which it should be positioned. */ - enum AnchorPoint - { - anchorAtLeftOrTop = 1 << 0, /**< The x or y co-ordinate specifies where the left or top edge of the rectangle should be. */ - anchorAtRightOrBottom = 1 << 1, /**< The x or y co-ordinate specifies where the right or bottom edge of the rectangle should be. */ - anchorAtCentre = 1 << 2 /**< The x or y co-ordinate specifies where the centre of the rectangle should be. */ - }; + Up to three Drawable objects can be given to this button, to represent the + 'normal', 'over' and 'down' states. - /** Specifies how an x or y co-ordinate should be interpreted. */ - enum PositionMode - { - absoluteFromParentTopLeft = 1 << 3, /**< The x or y co-ordinate specifies an absolute distance from the parent's top or left edge. */ - absoluteFromParentBottomRight = 1 << 4, /**< The x or y co-ordinate specifies an absolute distance from the parent's bottom or right edge. */ - absoluteFromParentCentre = 1 << 5, /**< The x or y co-ordinate specifies an absolute distance from the parent's centre. */ - proportionOfParentSize = 1 << 6 /**< The x or y co-ordinate specifies a proportion of the parent's width or height, measured from the parent's top or left. */ - }; + @see Button +*/ +class JUCE_API DrawableButton : public Button +{ +public: - /** Specifies how the width or height should be interpreted. */ - enum SizeMode + enum ButtonStyle { - absoluteSize = 1 << 0, /**< The width or height specifies an absolute size. */ - parentSizeMinusAbsolute = 1 << 1, /**< The width or height is an amount that should be subtracted from the parent's width or height. */ - proportionalSize = 1 << 2, /**< The width or height specifies a proportion of the parent's width or height. */ + ImageFitted, /**< The button will just display the images, but will resize and centre them to fit inside it. */ + ImageRaw, /**< The button will just display the images in their normal size and position. + This leaves it up to the caller to make sure the images are the correct size and position for the button. */ + ImageAboveTextLabel, /**< Draws the button as a text label across the bottom with the image resized and scaled to fit above it. */ + ImageOnButtonBackground /**< Draws the button as a standard rounded-rectangle button with the image on top. */ }; - /** Sets all options for all co-ordinates. - - This requires a reference rectangle to be specified, because if you're changing any - of the modes from proportional to absolute or vice-versa, then it'll need to convert - the co-ordinates, and will need to know the parent size so it can calculate this. - */ - void setModes (const AnchorPoint xAnchorMode, - const PositionMode xPositionMode, - const AnchorPoint yAnchorMode, - const PositionMode yPositionMode, - const SizeMode widthMode, - const SizeMode heightMode, - const Rectangle& targetSpaceToBeRelativeTo) throw(); - - /** Returns the anchoring mode for the x co-ordinate. - To change any of the modes, use setModes(). - */ - AnchorPoint getAnchorPointX() const throw(); - - /** Returns the positioning mode for the x co-ordinate. - To change any of the modes, use setModes(). - */ - PositionMode getPositionModeX() const throw(); - - /** Returns the raw x co-ordinate. + /** Creates a DrawableButton. - If the x position mode is absolute, then this will be the absolute value. If it's - proportional, then this will be a fractional proportion, where 1.0 means the full - width of the parent space. - */ - double getX() const throw() { return x; } + After creating one of these, use setImages() to specify the drawables to use. - /** Sets the raw value of the x co-ordinate. + @param buttonName the name to give the component + @param buttonStyle the layout to use - See getX() for the meaning of this value. + @see ButtonStyle, setButtonStyle, setImages */ - void setX (const double newX) throw() { x = newX; } + DrawableButton (const String& buttonName, + const ButtonStyle buttonStyle); - /** Returns the anchoring mode for the y co-ordinate. - To change any of the modes, use setModes(). - */ - AnchorPoint getAnchorPointY() const throw(); + /** Destructor. */ + ~DrawableButton(); - /** Returns the positioning mode for the y co-ordinate. - To change any of the modes, use setModes(). - */ - PositionMode getPositionModeY() const throw(); + /** Sets up the images to draw for the various button states. - /** Returns the raw y co-ordinate. + The button will keep its own internal copies of these drawables. - If the y position mode is absolute, then this will be the absolute value. If it's - proportional, then this will be a fractional proportion, where 1.0 means the full - height of the parent space. + @param normalImage the thing to draw for the button's 'normal' state. An internal copy + will be made of the object passed-in if it is non-zero. + @param overImage the thing to draw for the button's 'over' state - if this is + zero, the button's normal image will be used when the mouse is + over it. An internal copy will be made of the object passed-in + if it is non-zero. + @param downImage the thing to draw for the button's 'down' state - if this is + zero, the 'over' image will be used instead (or the normal image + as a last resort). An internal copy will be made of the object + passed-in if it is non-zero. + @param disabledImage an image to draw when the button is disabled. If this is zero, + the normal image will be drawn with a reduced opacity instead. + An internal copy will be made of the object passed-in if it is + non-zero. + @param normalImageOn same as the normalImage, but this is used when the button's toggle + state is 'on'. If this is 0, the normal image is used instead + @param overImageOn same as the overImage, but this is used when the button's toggle + state is 'on'. If this is 0, the normalImageOn is drawn instead + @param downImageOn same as the downImage, but this is used when the button's toggle + state is 'on'. If this is 0, the overImageOn is drawn instead + @param disabledImageOn same as the disabledImage, but this is used when the button's toggle + state is 'on'. If this is 0, the normal image will be drawn instead + with a reduced opacity */ - double getY() const throw() { return y; } - - /** Sets the raw value of the y co-ordinate. + void setImages (const Drawable* normalImage, + const Drawable* overImage = 0, + const Drawable* downImage = 0, + const Drawable* disabledImage = 0, + const Drawable* normalImageOn = 0, + const Drawable* overImageOn = 0, + const Drawable* downImageOn = 0, + const Drawable* disabledImageOn = 0); - See getY() for the meaning of this value. - */ - void setY (const double newY) throw() { y = newY; } + /** Changes the button's style. - /** Returns the mode used to calculate the width. - To change any of the modes, use setModes(). + @see ButtonStyle */ - SizeMode getWidthMode() const throw(); - - /** Returns the raw width value. + void setButtonStyle (const ButtonStyle newStyle); - If the width mode is absolute, then this will be the absolute value. If the mode is - proportional, then this will be a fractional proportion, where 1.0 means the full - width of the parent space. - */ - double getWidth() const throw() { return w; } + /** Changes the button's background colours. - /** Sets the raw width value. + The toggledOffColour is the colour to use when the button's toggle state + is off, and toggledOnColour when it's on. - See getWidth() for the details about what this value means. - */ - void setWidth (const double newWidth) throw() { w = newWidth; } + For an ImageOnly or ImageAboveTextLabel style, the background colour is + used to fill the background of the component. - /** Returns the mode used to calculate the height. - To change any of the modes, use setModes(). + For an ImageOnButtonBackground style, the colour is used to draw the + button's lozenge shape and exactly how the colour's used will depend + on the LookAndFeel. */ - SizeMode getHeightMode() const throw(); + void setBackgroundColours (const Colour& toggledOffColour, + const Colour& toggledOnColour); - /** Returns the raw height value. + /** Returns the current background colour being used. - If the height mode is absolute, then this will be the absolute value. If the mode is - proportional, then this will be a fractional proportion, where 1.0 means the full - height of the parent space. + @see setBackgroundColour */ - double getHeight() const throw() { return h; } + const Colour& getBackgroundColour() const throw(); - /** Sets the raw height value. + /** Gives the button an optional amount of space around the edge of the drawable. - See getHeight() for the details about what this value means. - */ - void setHeight (const double newHeight) throw() { h = newHeight; } + This will only apply to ImageFitted or ImageRaw styles, it won't affect the + ones on a button background. If the button is too small for the given gap, a + smaller gap will be used. - /** If the size and position are constance, and wouldn't be affected by changes - in the parent's size, then this will return true. + By default there's a gap of about 3 pixels. */ - bool isPositionAbsolute() const throw(); - - /** Compares two objects. */ - const bool operator== (const PositionedRectangle& other) const throw(); + void setEdgeIndent (const int numPixelsIndent); - /** Compares two objects. */ - const bool operator!= (const PositionedRectangle& other) const throw(); + /** Returns the image that the button is currently displaying. */ + const Drawable* getCurrentImage() const throw(); + const Drawable* getNormalImage() const throw(); + const Drawable* getOverImage() const throw(); + const Drawable* getDownImage() const throw(); juce_UseDebuggingNewOperator +protected: + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); + private: - double x, y, w, h; - uint8 xMode, yMode, wMode, hMode; - void addPosDescription (String& result, const uint8 mode, const double value) const throw(); - void addSizeDescription (String& result, const uint8 mode, const double value) const throw(); - void decodePosString (const String& s, uint8& mode, double& value) throw(); - void decodeSizeString (const String& s, uint8& mode, double& value) throw(); - void applyPosAndSize (double& xOut, double& wOut, const double x, const double w, - const uint8 xMode, const uint8 wMode, - const int parentPos, const int parentSize) const throw(); - void updatePosAndSize (double& xOut, double& wOut, double x, const double w, - const uint8 xMode, const uint8 wMode, - const int parentPos, const int parentSize) const throw(); -}; + ButtonStyle style; + Drawable* normalImage; + Drawable* overImage; + Drawable* downImage; + Drawable* disabledImage; + Drawable* normalImageOn; + Drawable* overImageOn; + Drawable* downImageOn; + Drawable* disabledImageOn; + Colour backgroundOff, backgroundOn; + int edgeIndent; -#endif // __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ -/********* End of inlined file: juce_PositionedRectangle.h *********/ + void deleteImages(); + DrawableButton (const DrawableButton&); + const DrawableButton& operator= (const DrawableButton&); +}; -#endif -#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ +#endif // __JUCE_DRAWABLEBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_DrawableButton.h *********/ #endif -#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ +#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ -/********* Start of inlined file: juce_PathIterator.h *********/ -#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ -#define __JUCE_PATHITERATOR_JUCEHEADER__ +/********* Start of inlined file: juce_HyperlinkButton.h *********/ +#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ +#define __JUCE_HYPERLINKBUTTON_JUCEHEADER__ /** - Flattens a Path object into a series of straight-line sections. - - Use one of these to iterate through a Path object, and it will convert - all the curves into line sections so it's easy to render or perform - geometric operations on. + A button showing an underlined weblink, that will launch the link + when it's clicked. - @see Path + @see Button */ -class JUCE_API PathFlatteningIterator +class JUCE_API HyperlinkButton : public Button { public: - /** Creates a PathFlatteningIterator. - - After creation, use the next() method to initialise the fields in the - object with the first line's position. + /** Creates a HyperlinkButton. - @param path the path to iterate along - @param transform a transform to apply to each point in the path being iterated - @param tolerence the amount by which the curves are allowed to deviate from the - lines into which they are being broken down - a higher tolerence - is a bit faster, but less smooth. + @param linkText the text that will be displayed in the button - this is + also set as the Component's name, but the text can be + changed later with the Button::getButtonText() method + @param linkURL the URL to launch when the user clicks the button */ - PathFlatteningIterator (const Path& path, - const AffineTransform& transform = AffineTransform::identity, - float tolerence = 6.0f) throw(); + HyperlinkButton (const String& linkText, + const URL& linkURL); /** Destructor. */ - ~PathFlatteningIterator() throw(); - - /** Fetches the next line segment from the path. + ~HyperlinkButton(); - This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath - so that they describe the new line segment. + /** Changes the font to use for the text. - @returns false when there are no more lines to fetch. + If resizeToMatchComponentHeight is true, the font's height will be adjusted + to match the size of the component. */ - bool next() throw(); + void setFont (const Font& newFont, + const bool resizeToMatchComponentHeight, + const Justification& justificationType = Justification::horizontallyCentred); - /** The x position of the start of the current line segment. */ - float x1; - /** The y position of the start of the current line segment. */ - float y1; - /** The x position of the end of the current line segment. */ - float x2; - /** The y position of the end of the current line segment. */ - float y2; + /** A set of colour IDs to use to change the colour of various aspects of the link. - /** Indicates whether the current line segment is closing a sub-path. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - If the current line is the one that connects the end of a sub-path - back to the start again, this will be true. + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - bool closesSubPath; + enum ColourIds + { + textColourId = 0x1001f00, /**< The colour to use for the URL text. */ + }; - /** The index of the current line within the current sub-path. + /** Changes the URL that the button will trigger. */ + void setURL (const URL& newURL) throw(); - E.g. you can use this to see whether the line is the first one in the - subpath by seeing if it's 0. - */ - int subPathIndex; + /** Returns the URL that the button will trigger. */ + const URL& getURL() const throw() { return url; } - /** Returns true if the current segment is the last in the current sub-path. */ - bool isLastInSubpath() const throw() { return stackPos == stackBase - && (index >= path.numElements - || points [index] == Path::moveMarker); } + /** Resizes the button horizontally to fit snugly around the text. + + This won't affect the button's height. + */ + void changeWidthToFitText(); juce_UseDebuggingNewOperator +protected: + /** @internal */ + void clicked(); + /** @internal */ + void colourChanged(); + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); + private: - const Path& path; - const AffineTransform transform; - float* points; - float tolerence, subPathCloseX, subPathCloseY; - bool isIdentityTransform; + URL url; + Font font; + bool resizeFont; + Justification justification; - float* stackBase; - float* stackPos; - int index, stackSize; + const Font getFontToUse() const; - PathFlatteningIterator (const PathFlatteningIterator&); - const PathFlatteningIterator& operator= (const PathFlatteningIterator&); + HyperlinkButton (const HyperlinkButton&); + const HyperlinkButton& operator= (const HyperlinkButton&); }; -#endif // __JUCE_PATHITERATOR_JUCEHEADER__ -/********* End of inlined file: juce_PathIterator.h *********/ - -#endif -#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ +#endif // __JUCE_HYPERLINKBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_HyperlinkButton.h *********/ #endif -#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ - -/********* Start of inlined file: juce_CameraDevice.h *********/ -#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ -#define __JUCE_CAMERADEVICE_JUCEHEADER__ +#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ -#if JUCE_USE_CAMERA +/********* Start of inlined file: juce_ImageButton.h *********/ +#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ +#define __JUCE_IMAGEBUTTON_JUCEHEADER__ /** - Receives callbacks with images from a CameraDevice. + As the title suggests, this is a button containing an image. - @see CameraDevice::addListener + The colour and transparency of the image can be set to vary when the + button state changes. + + @see Button, ShapeButton, TextButton */ -class CameraImageListener +class JUCE_API ImageButton : public Button { public: - CameraImageListener() {} - virtual ~CameraImageListener() {} - /** This method is called when a new image arrives. + /** Creates an ImageButton. - This may be called by any thread, so be careful about thread-safety, - and make sure that you process the data as quickly as possible to - avoid glitching! - */ - virtual void imageReceived (Image& image) = 0; -}; - -/** - Controls any camera capture devices that might be available. - - Use getAvailableDevices() to list the devices that are attached to the - system, then call openDevice to open one for use. Once you have a CameraDevice - object, you can get a viewer component from it, and use its methods to - stream to a file or capture still-frames. -*/ -class JUCE_API CameraDevice -{ -public: - /** Destructor. */ - virtual ~CameraDevice(); - - /** Returns a list of the available cameras on this machine. - - You can open one of these devices by calling openDevice(). - */ - static const StringArray getAvailableDevices(); - - /** Opens a camera device. - - The index parameter indicates which of the items returned by getAvailableDevices() - to open. - - The size constraints allow the method to choose between different resolutions if - the camera supports this. If the resolution cam't be specified (e.g. on the Mac) - then these will be ignored. - */ - static CameraDevice* openDevice (int deviceIndex, - int minWidth = 128, int minHeight = 64, - int maxWidth = 1024, int maxHeight = 768); - - /** Returns the name of this device */ - const String getName() const throw() { return name; } + Use setImage() to specify the image to use. The colours and opacities that + are specified here can be changed later using setDrawingOptions(). - /** Creates a component that can be used to display a preview of the - video from this camera. + @param name the name to give the component */ - Component* createViewerComponent(); - - /** Starts recording video to the specified file. + ImageButton (const String& name); - You should use getFileExtension() to find out the correct extension to - use for your filename. + /** Destructor. */ + ~ImageButton(); - If the file exists, it will be deleted before the recording starts. + /** Sets up the images to draw in various states. - This method may not start recording instantly, so if you need to know the - exact time at which the file begins, you can call getTimeOfFirstRecordedFrame() - after the recording has finished. - */ - void startRecordingToFile (const File& file); + Important! Bear in mind that if you pass the same image in for more than one of + these parameters, this button will delete it (or release from the ImageCache) + multiple times! - /** Stops recording, after a call to startRecordingToFile(). + @param resizeButtonNowToFitThisImage if true, the button will be immediately + resized to the same dimensions as the normal image + @param rescaleImagesWhenButtonSizeChanges if true, the image will be rescaled to fit the + button when the button's size changes + @param preserveImageProportions if true then any rescaling of the image to fit + the button will keep the image's x and y proportions + correct - i.e. it won't distort its shape, although + this might create gaps around the edges + @param normalImage the image to use when the button is in its normal state. The + image passed in will be deleted (or released if it + was created by the ImageCache class) when the + button no longer needs it. + @param imageOpacityWhenNormal the opacity to use when drawing the normal image. + @param overlayColourWhenNormal an overlay colour to use to fill the alpha channel of the + normal image - if this colour is transparent, no overlay + will be drawn. The overlay will be drawn over the top of the + image, so you can basically add a solid or semi-transparent + colour to the image to brighten or darken it + @param overImage the image to use when the mouse is over the button. If + you want to use the same image as was set in the normalImage + parameter, this value can be 0. As for normalImage, it + will be deleted or released by the button when no longer + needed + @param imageOpacityWhenOver the opacity to use when drawing the image when the mouse + is over the button + @param overlayColourWhenOver an overlay colour to use to fill the alpha channel of the + image when the mouse is over - if this colour is transparent, + no overlay will be drawn + @param downImage an image to use when the button is pressed down. If set + to zero, the 'over' image will be drawn instead (or the + normal image if there isn't an 'over' image either). This + image will be deleted or released by the button when no + longer needed + @param imageOpacityWhenDown the opacity to use when drawing the image when the button + is pressed + @param overlayColourWhenDown an overlay colour to use to fill the alpha channel of the + image when the button is pressed down - if this colour is + transparent, no overlay will be drawn + @param hitTestAlphaThreshold if set to zero, the mouse is considered to be over the button + whenever it's inside the button's bounding rectangle. If + set to values higher than 0, the mouse will only be + considered to be over the image when the value of the + image's alpha channel at that position is greater than + this level. */ - void stopRecording(); + void setImages (const bool resizeButtonNowToFitThisImage, + const bool rescaleImagesWhenButtonSizeChanges, + const bool preserveImageProportions, + Image* const normalImage, + const float imageOpacityWhenNormal, + const Colour& overlayColourWhenNormal, + Image* const overImage, + const float imageOpacityWhenOver, + const Colour& overlayColourWhenOver, + Image* const downImage, + const float imageOpacityWhenDown, + const Colour& overlayColourWhenDown, + const float hitTestAlphaThreshold = 0.0f); - /** Returns the file extension that should be used for the files - that you pass to startRecordingToFile(). + /** Returns the currently set 'normal' image. */ + Image* getNormalImage() const throw(); - This may be platform-specific, e.g. ".mov" or ".avi". - */ - static const String getFileExtension(); + /** Returns the image that's drawn when the mouse is over the button. - /** After calling stopRecording(), this method can be called to return the timestamp - of the first frame that was written to the file. + If an 'over' image has been set, this will return it; otherwise it'll + just return the normal image. */ - const Time getTimeOfFirstRecordedFrame() const; - - /** Adds a listener to receive images from the camera. + Image* getOverImage() const throw(); - Be very careful not to delete the listener without first removing it by calling - removeListener(). - */ - void addListener (CameraImageListener* listenerToAdd); + /** Returns the image that's drawn when the button is held down. - /** Removes a listener that was previously added with addListener(). + If a 'down' image has been set, this will return it; otherwise it'll + return the 'over' image or normal image, depending on what's available. */ - void removeListener (CameraImageListener* listenerToRemove); + Image* getDownImage() const throw(); juce_UseDebuggingNewOperator protected: /** @internal */ - CameraDevice (const String& name, int index); + bool hitTest (int x, int y); + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); private: - void* internal; - bool isRecording; - String name; - CameraDevice (const CameraDevice&); - const CameraDevice& operator= (const CameraDevice&); + bool scaleImageToFit, preserveProportions; + unsigned char alphaThreshold; + int imageX, imageY, imageW, imageH; + Image* normalImage; + Image* overImage; + Image* downImage; + float normalOpacity, overOpacity, downOpacity; + Colour normalOverlay, overOverlay, downOverlay; + + Image* getCurrentImage() const; + void deleteImages(); + + ImageButton (const ImageButton&); + const ImageButton& operator= (const ImageButton&); }; -#endif -#endif // __JUCE_CAMERADEVICE_JUCEHEADER__ -/********* End of inlined file: juce_CameraDevice.h *********/ +#endif // __JUCE_IMAGEBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_ImageButton.h *********/ #endif -#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ +#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ -/********* Start of inlined file: juce_ImageCache.h *********/ -#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ -#define __JUCE_IMAGECACHE_JUCEHEADER__ +/********* Start of inlined file: juce_ShapeButton.h *********/ +#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ +#define __JUCE_SHAPEBUTTON_JUCEHEADER__ /** - A global cache of images that have been loaded from files or memory. - - If you're loading an image and may need to use the image in more than one - place, this is used to allow the same image to be shared rather than loading - multiple copies into memory. - - Another advantage is that after images are released, they will be kept in - memory for a few seconds before it is actually deleted, so if you're repeatedly - loading/deleting the same image, it'll reduce the chances of having to reload it - each time. + A button that contains a filled shape. - @see Image, ImageFileFormat + @see Button, ImageButton, TextButton, ArrowButton */ -class JUCE_API ImageCache : private DeletedAtShutdown, - private Timer +class JUCE_API ShapeButton : public Button { public: - /** Loads an image from a file, (or just returns the image if it's already cached). + /** Creates a ShapeButton. - If the cache already contains an image that was loaded from this file, - that image will be returned. Otherwise, this method will try to load the - file, add it to the cache, and return it. + @param name a name to give the component - see Component::setName() + @param normalColour the colour to fill the shape with when the mouse isn't over + @param overColour the colour to use when the mouse is over the shape + @param downColour the colour to use when the button is in the pressed-down state + */ + ShapeButton (const String& name, + const Colour& normalColour, + const Colour& overColour, + const Colour& downColour); - It's very important not to delete the image that is returned - instead use - the ImageCache::release() method. + /** Destructor. */ + ~ShapeButton(); - Also, remember that the image returned is shared, so drawing into it might - affect other things that are using it! + /** Sets the shape to use. - @param file the file to try to load - @returns the image, or null if it there was an error loading it - @see release, getFromMemory, getFromCache, ImageFileFormat::loadFrom + @param newShape the shape to use + @param resizeNowToFitThisShape if true, the button will be resized to fit the shape's bounds + @param maintainShapeProportions if true, the shape's proportions will be kept fixed when + the button is resized + @param hasDropShadow if true, the button will be given a drop-shadow effect */ - static Image* getFromFile (const File& file); - - /** Loads an image from an in-memory image file, (or just returns the image if it's already cached). + void setShape (const Path& newShape, + const bool resizeNowToFitThisShape, + const bool maintainShapeProportions, + const bool hasDropShadow); - If the cache already contains an image that was loaded from this block of memory, - that image will be returned. Otherwise, this method will try to load the - file, add it to the cache, and return it. + /** Set the colours to use for drawing the shape. - It's very important not to delete the image that is returned - instead use - the ImageCache::release() method. + @param normalColour the colour to fill the shape with when the mouse isn't over + @param overColour the colour to use when the mouse is over the shape + @param downColour the colour to use when the button is in the pressed-down state + */ + void setColours (const Colour& normalColour, + const Colour& overColour, + const Colour& downColour); - Also, remember that the image returned is shared, so drawing into it might - affect other things that are using it! + /** Sets up an outline to draw around the shape. - @param imageData the block of memory containing the image data - @param dataSize the data size in bytes - @returns the image, or null if it there was an error loading it - @see release, getFromMemory, getFromCache, ImageFileFormat::loadFrom + @param outlineColour the colour to use + @param outlineStrokeWidth the thickness of line to draw */ - static Image* getFromMemory (const void* imageData, - const int dataSize); + void setOutline (const Colour& outlineColour, + const float outlineStrokeWidth); - /** Releases an image that was previously created by the ImageCache. + juce_UseDebuggingNewOperator - If an image has been returned by the getFromFile() or getFromMemory() methods, - it mustn't be deleted directly, but should be released with this method - instead. +protected: + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); - @see getFromFile, getFromMemory - */ - static void release (Image* const imageToRelease); +private: + Colour normalColour, overColour, downColour, outlineColour; + DropShadowEffect shadow; + Path shape; + bool maintainShapeProportions; + float outlineWidth; - /** Checks whether an image is in the cache or not. + ShapeButton (const ShapeButton&); + const ShapeButton& operator= (const ShapeButton&); +}; - @returns true if the image is currently in the cache - */ - static bool isImageInCache (Image* const imageToLookFor); +#endif // __JUCE_SHAPEBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_ShapeButton.h *********/ - /** Increments the reference-count for a cached image. +#endif +#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ - If the image isn't in the cache, this method won't do anything. - */ - static void incReferenceCount (Image* const image); +#endif +#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ - /** Checks the cache for an image with a particular hashcode. +/********* Start of inlined file: juce_ToggleButton.h *********/ +#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ +#define __JUCE_TOGGLEBUTTON_JUCEHEADER__ - If there's an image in the cache with this hashcode, it will be returned, - otherwise it will return zero. +/** + A button that can be toggled on/off. - If an image is returned, it must be released with the release() method - when no longer needed, to maintain the correct reference counts. + All buttons can be toggle buttons, but this lets you create one of the + standard ones which has a tick-box and a text label next to it. - @param hashCode the hash code that would have been associated with the - image by addImageToCache() - @see addImageToCache - */ - static Image* getFromHashCode (const int64 hashCode); + @see Button, DrawableButton, TextButton +*/ +class JUCE_API ToggleButton : public Button +{ +public: - /** Adds an image to the cache with a user-defined hash-code. + /** Creates a ToggleButton. - After calling this, responsibilty for deleting the image will be taken - by the ImageCache. + @param buttonText the text to put in the button (the component's name is also + initially set to this string, but these can be changed later + using the setName() and setButtonText() methods) + */ + ToggleButton (const String& buttonText); - The image will be initially be given a reference count of 1, so call - the release() method to delete it. + /** Destructor. */ + ~ToggleButton(); - @param image the image to add - @param hashCode the hash-code to associate with it - @see getFromHashCode + /** Resizes the button to fit neatly around its current text. + + The button's height won't be affected, only its width. */ - static void addImageToCache (Image* const image, - const int64 hashCode); + void changeWidthToFitText(); - /** Changes the amount of time before an unused image will be removed from the cache. + /** A set of colour IDs to use to change the colour of various aspects of the button. - By default this is about 5 seconds. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - static void setCacheTimeout (const int millisecs); + enum ColourIds + { + textColourId = 0x1006501 /**< The colour to use for the button's text. */ + }; juce_UseDebuggingNewOperator -private: +protected: + /** @internal */ + void paintButton (Graphics& g, + bool isMouseOverButton, + bool isButtonDown); - CriticalSection lock; - VoidArray images; + /** @internal */ + void colourChanged(); - ImageCache() throw(); - ImageCache (const ImageCache&); - const ImageCache& operator= (const ImageCache&); - ~ImageCache(); +private: - void timerCallback(); + ToggleButton (const ToggleButton&); + const ToggleButton& operator= (const ToggleButton&); }; -#endif // __JUCE_IMAGECACHE_JUCEHEADER__ -/********* End of inlined file: juce_ImageCache.h *********/ +#endif // __JUCE_TOGGLEBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_ToggleButton.h *********/ #endif -#ifndef __JUCE_IMAGE_JUCEHEADER__ +#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ -#endif -#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ +/********* Start of inlined file: juce_ToolbarButton.h *********/ +#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ +#define __JUCE_TOOLBARBUTTON_JUCEHEADER__ -/********* Start of inlined file: juce_ImageFileFormat.h *********/ -#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ -#define __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ +/********* Start of inlined file: juce_ToolbarItemComponent.h *********/ +#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ +#define __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_Toolbar.h *********/ +#ifndef __JUCE_TOOLBAR_JUCEHEADER__ +#define __JUCE_TOOLBAR_JUCEHEADER__ + +/********* Start of inlined file: juce_DragAndDropContainer.h *********/ +#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ +#define __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ + +/********* Start of inlined file: juce_DragAndDropTarget.h *********/ +#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ +#define __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ /** - Base-class for codecs that can read and write image file formats such - as PNG, JPEG, etc. + Components derived from this class can have things dropped onto them by a DragAndDropContainer. - This class also contains static methods to make it easy to load images - from files, streams or from memory. + To create a component that can receive things drag-and-dropped by a DragAndDropContainer, + derive your component from this class, and make sure that it is somewhere inside a + DragAndDropContainer component. - @see Image, ImageCache + Note: If all that you need to do is to respond to files being drag-and-dropped from + the operating system onto your component, you don't need any of these classes: instead + see the FileDragAndDropTarget class. + + @see DragAndDropContainer, FileDragAndDropTarget */ -class JUCE_API ImageFileFormat +class JUCE_API DragAndDropTarget { -protected: - - /** Creates an ImageFormat. */ - ImageFileFormat() throw() {} - public: /** Destructor. */ - virtual ~ImageFileFormat() throw() {} + virtual ~DragAndDropTarget() {} - /** Returns a description of this file format. + /** Callback to check whether this target is interested in the type of object being + dragged. - E.g. "JPEG", "PNG" + @param sourceDescription the description string passed into DragAndDropContainer::startDragging() + @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() + @returns true if this component wants to receive the other callbacks regarging this + type of object; if it returns false, no other callbacks will be made. */ - virtual const String getFormatName() = 0; - - /** Returns true if the given stream seems to contain data that this format - understands. - - The format class should only read the first few bytes of the stream and sniff - for header bytes that it understands. + virtual bool isInterestedInDragSource (const String& sourceDescription, + Component* sourceComponent) = 0; - @see decodeImage - */ - virtual bool canUnderstand (InputStream& input) = 0; + /** Callback to indicate that something is being dragged over this component. - /** Tries to decode and return an image from the given stream. + This gets called when the user moves the mouse into this component while dragging + something. - This will be called for an image format after calling its canUnderStand() method - to see if it can handle the stream. + Use this callback as a trigger to make your component repaint itself to give the + user feedback about whether the item can be dropped here or not. - @param input the stream to read the data from. The stream will be positioned - at the start of the image data (but this may not necessarily - be position 0) - @returns the image that was decoded, or 0 if it fails. It's the - caller's responsibility to delete this image when no longer needed. - @see loadFrom + @param sourceDescription the description string passed into DragAndDropContainer::startDragging() + @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component + @see itemDragExit */ - virtual Image* decodeImage (InputStream& input) = 0; + virtual void itemDragEnter (const String& sourceDescription, + Component* sourceComponent, + int x, + int y); - /** Attempts to write an image to a stream. + /** Callback to indicate that the user is dragging something over this component. - To specify extra information like encoding quality, there will be appropriate parameters - in the subclasses of the specific file types. + This gets called when the user moves the mouse over this component while dragging + something. Normally overriding itemDragEnter() and itemDragExit() are enough, but + this lets you know what happens in-between. - @returns true if it nothing went wrong. + @param sourceDescription the description string passed into DragAndDropContainer::startDragging() + @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component */ - virtual bool writeImageToStream (const Image& sourceImage, - OutputStream& destStream) = 0; + virtual void itemDragMove (const String& sourceDescription, + Component* sourceComponent, + int x, + int y); - /** Tries the built-in decoders to see if it can find one to read this stream. + /** Callback to indicate that something has been dragged off the edge of this component. - There are currently built-in decoders for PNG, JPEG and GIF formats. + This gets called when the user moves the mouse out of this component while dragging + something. - The object that is returned should not be deleted by the caller. + If you've used itemDragEnter() to repaint your component and give feedback, use this + as a signal to repaint it in its normal state. - @see canUnderstand, decodeImage, loadFrom + @param sourceDescription the description string passed into DragAndDropContainer::startDragging() + @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() + @see itemDragEnter */ - static ImageFileFormat* findImageFormatForStream (InputStream& input); + virtual void itemDragExit (const String& sourceDescription, + Component* sourceComponent); - /** Tries to load an image from a stream. + /** Callback to indicate that the user has dropped something onto this component. - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. + When the user drops an item this get called, and you can use the description to + work out whether your object wants to deal with it or not. - @returns the image that was decoded, or 0 if it fails to load one. It's the - caller's responsibility to delete this image when no longer needed. - */ - static Image* loadFrom (InputStream& input); + Note that after this is called, the itemDragExit method may not be called, so you should + clean up in here if there's anything you need to do when the drag finishes. - /** Tries to load an image from a file. + @param sourceDescription the description string passed into DragAndDropContainer::startDragging() + @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component + */ + virtual void itemDropped (const String& sourceDescription, + Component* sourceComponent, + int x, + int y) = 0; - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. + /** Overriding this allows the target to tell the drag container whether to + draw the drag image while the cursor is over it. - @returns the image that was decoded, or 0 if it fails to load one. It's the - caller's responsibility to delete this image when no longer needed. + By default it returns true, but if you return false, then the normal drag + image will not be shown when the cursor is over this target. */ - static Image* loadFrom (const File& file); + virtual bool shouldDrawDragImageWhenOver(); +}; - /** Tries to load an image from a block of raw image data. +#endif // __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ +/********* End of inlined file: juce_DragAndDropTarget.h *********/ - This will use the findImageFormatForStream() method to locate a suitable - codec, and use that to load the image. +/** + Enables drag-and-drop behaviour for a component and all its sub-components. - @returns the image that was decoded, or 0 if it fails to load one. It's the - caller's responsibility to delete this image when no longer needed. - */ - static Image* loadFrom (const void* rawData, - const int numBytesOfData); + For a component to be able to make or receive drag-and-drop events, one of its parent + components must derive from this class. It's probably best for the top-level + component to implement it. -}; + Then to start a drag operation, any sub-component can just call the startDragging() + method, and this object will take over, tracking the mouse and sending appropriate + callbacks to any child components derived from DragAndDropTarget which the mouse + moves over. -/** - A type of ImageFileFormat for reading and writing PNG files. + Note: If all that you need to do is to respond to files being drag-and-dropped from + the operating system onto your component, you don't need any of these classes: you can do this + simply by overriding Component::filesDropped(). - @see ImageFileFormat, JPEGImageFormat + @see DragAndDropTarget */ -class JUCE_API PNGImageFormat : public ImageFileFormat +class JUCE_API DragAndDropContainer { public: - PNGImageFormat() throw(); - ~PNGImageFormat() throw(); + /** Creates a DragAndDropContainer. - const String getFormatName(); - bool canUnderstand (InputStream& input); + The object that derives from this class must also be a Component. + */ + DragAndDropContainer(); - Image* decodeImage (InputStream& input); + /** Destructor. */ + virtual ~DragAndDropContainer(); - bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); -}; + /** Begins a drag-and-drop operation. -/** - A type of ImageFileFormat for reading and writing JPEG files. + This starts a drag-and-drop operation - call it when the user drags the + mouse in your drag-source component, and this object will track mouse + movements until the user lets go of the mouse button, and will send + appropriate messages to DragAndDropTarget objects that the mouse moves + over. - @see ImageFileFormat, PNGImageFormat -*/ -class JUCE_API JPEGImageFormat : public ImageFileFormat -{ -public: + findParentDragContainerFor() is a handy method to call to find the + drag container to use for a component. - JPEGImageFormat() throw(); - ~JPEGImageFormat() throw(); + @param sourceDescription a string to use as the description of the thing being + dragged - this will be passed to the objects that might be + dropped-onto so they can decide if they want to handle it or + not + @param sourceComponent the component that is being dragged + @param dragImage the image to drag around underneath the mouse. If this is + zero, a snapshot of the sourceComponent will be used instead. An + image passed-in will be deleted by this object when no longer + needed. + @param allowDraggingToOtherJuceWindows if true, the dragged component will appear as a desktop + window, and can be dragged to DragAndDropTargets that are the + children of components other than this one. + @param imageOffsetFromMouse if an image has been passed-in, this specifies the offset + at which the image should be drawn from the mouse. If it isn't + specified, then the image will be centred around the mouse. If + an image hasn't been passed-in, this will be ignored. + */ + void startDragging (const String& sourceDescription, + Component* sourceComponent, + Image* dragImage = 0, + const bool allowDraggingToOtherJuceWindows = false, + const Point* imageOffsetFromMouse = 0); - /** Specifies the quality to be used when writing a JPEG file. + /** Returns true if something is currently being dragged. */ + bool isDragAndDropActive() const; - @param newQuality a value 0 to 1.0, where 0 is low quality, 1.0 is best, or - any negative value is "default" quality + /** Returns the description of the thing that's currently being dragged. + + If nothing's being dragged, this will return an empty string, otherwise it's the + string that was passed into startDragging(). + + @see startDragging */ - void setQuality (const float newQuality); + const String getCurrentDragDescription() const; - const String getFormatName(); + /** Utility to find the DragAndDropContainer for a given Component. - bool canUnderstand (InputStream& input); + This will search up this component's parent hierarchy looking for the first + parent component which is a DragAndDropContainer. - Image* decodeImage (InputStream& input); + It's useful when a component wants to call startDragging but doesn't know + the DragAndDropContainer it should to use. - bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); + Obviously this may return 0 if it doesn't find a suitable component. + */ + static DragAndDropContainer* findParentDragContainerFor (Component* childComponent); + + /** This performs a synchronous drag-and-drop of a set of files to some external + application. + + You can call this function in response to a mouseDrag callback, and it will + block, running its own internal message loop and tracking the mouse, while it + uses a native operating system drag-and-drop operation to move or copy some + files to another application. + + @param files a list of filenames to drag + @param canMoveFiles if true, the app that receives the files is allowed to move the files to a new location + (if this is appropriate). If false, the receiver is expected to make a copy of them. + @returns true if the files were successfully dropped somewhere, or false if it + was interrupted + @see performExternalDragDropOfText + */ + static bool performExternalDragDropOfFiles (const StringArray& files, const bool canMoveFiles); + + /** This performs a synchronous drag-and-drop of a block of text to some external + application. + + You can call this function in response to a mouseDrag callback, and it will + block, running its own internal message loop and tracking the mouse, while it + uses a native operating system drag-and-drop operation to move or copy some + text to another application. + + @param text the text to copy + @returns true if the text was successfully dropped somewhere, or false if it + was interrupted + @see performExternalDragDropOfFiles + */ + static bool performExternalDragDropOfText (const String& text); + + juce_UseDebuggingNewOperator + +protected: + /** Override this if you want to be able to perform an external drag a set of files + when the user drags outside of this container component. + + This method will be called when a drag operation moves outside the Juce-based window, + and if you want it to then perform a file drag-and-drop, add the filenames you want + to the array passed in, and return true. + + @param dragSourceDescription the description passed into the startDrag() call when the drag began + @param dragSourceComponent the component passed into the startDrag() call when the drag began + @param files on return, the filenames you want to drag + @param canMoveFiles on return, true if it's ok for the receiver to move the files; false if + it must make a copy of them (see the performExternalDragDropOfFiles() + method) + @see performExternalDragDropOfFiles + */ + virtual bool shouldDropFilesWhenDraggedExternally (const String& dragSourceDescription, + Component* dragSourceComponent, + StringArray& files, + bool& canMoveFiles); private: - float quality; + friend class DragImageComponent; + Component* dragImageComponent; + String currentDragDesc; }; -#endif // __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ -/********* End of inlined file: juce_ImageFileFormat.h *********/ - -#endif -#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ +#endif // __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ +/********* End of inlined file: juce_DragAndDropContainer.h *********/ -/********* Start of inlined file: juce_ImageConvolutionKernel.h *********/ -#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ -#define __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ +/********* Start of inlined file: juce_ComponentAnimator.h *********/ +#ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ +#define __JUCE_COMPONENTANIMATOR_JUCEHEADER__ /** - Represents a filter kernel to use in convoluting an image. + Animates a set of components, moving it to a new position. - @see Image::applyConvolution + To use this, create a ComponentAnimator, and use its animateComponent() method + to tell it to move components to destination positions. Any number of + components can be animated by one ComponentAnimator object (if you've got a + lot of components to move, it's much more efficient to share a single animator + than to have many animators running at once). + + You'll need to make sure the animator object isn't deleted before it finishes + moving the components. + + The class is a ChangeBroadcaster and sends a notification when any components + start or finish being animated. */ -class JUCE_API ImageConvolutionKernel +class JUCE_API ComponentAnimator : public ChangeBroadcaster, + private Timer { public: - /** Creates an empty convulution kernel. - - @param size the length of each dimension of the kernel, so e.g. if the size - is 5, it will create a 5x5 kernel - */ - ImageConvolutionKernel (const int size) throw(); + /** Creates a ComponentAnimator. */ + ComponentAnimator(); /** Destructor. */ - ~ImageConvolutionKernel() throw(); + ~ComponentAnimator(); - /** Resets all values in the kernel to zero. - */ - void clear() throw(); + /** Starts a component moving from its current position to a specified position. - /** Sets the value of a specific cell in the kernel. + If the component is already in the middle of an animation, that will be abandoned, + and a new animation will begin, moving the component from its current location. - The x and y parameters must be in the range 0 < x < getKernelSize(). + The start and end speed parameters let you apply some acceleration to the component's + movement. - @see setOverallSum + @param component the component to move + @param finalPosition the destination position and size to move it to + @param millisecondsToSpendMoving how long, in milliseconds, it should take + to arrive at its destination + @param startSpeed a value to indicate the relative start speed of the + animation. If this is 0, the component will start + by accelerating from rest; higher values mean that it + will have an initial speed greater than zero. If the + value if greater than 1, it will decelerate towards the + middle of its journey. To move the component at a constant + rate for its entire animation, set both the start and + end speeds to 1.0 + @param endSpeed a relative speed at which the component should be moving + when the animation finishes. If this is 0, the component + will decelerate to a standstill at its final position; higher + values mean the component will still be moving when it stops. + To move the component at a constant rate for its entire + animation, set both the start and end speeds to 1.0 */ - void setKernelValue (const int x, - const int y, - const float value) throw(); + void animateComponent (Component* const component, + const Rectangle& finalPosition, + const int millisecondsToSpendMoving, + const double startSpeed = 1.0, + const double endSpeed = 1.0); - /** Rescales all values in the kernel to make the total add up to a fixed value. + /** Stops a component if it's currently being animated. - This will multiply all values in the kernel by (desiredTotalSum / currentTotalSum). + If moveComponentToItsFinalPosition is true, then the component will + be immediately moved to its destination position and size. If false, it will be + left in whatever location it currently occupies. */ - void setOverallSum (const float desiredTotalSum) throw(); - - /** Multiplies all values in the kernel by a value. */ - void rescaleAllValues (const float multiplier) throw(); + void cancelAnimation (Component* const component, + const bool moveComponentToItsFinalPosition); - /** Intialises the kernel for a gaussian blur. + /** Clears all of the active animations. - @param blurRadius this may be larger or smaller than the kernel's actual - size but this will obviously be wasteful or clip at the - edges. Ideally the kernel should be just larger than - (blurRadius * 2). + If moveComponentsToTheirFinalPositions is true, all the components will + be immediately set to their final positions. If false, they will be + left in whatever locations they currently occupy. */ - void createGaussianBlur (const float blurRadius) throw(); - - /** Returns the size of the kernel. + void cancelAllAnimations (const bool moveComponentsToTheirFinalPositions); - E.g. if it's a 3x3 kernel, this returns 3. - */ - int getKernelSize() const throw() { return size; } + /** Returns the destination position for a component. - /** Returns a 2-dimensional array of the kernel's values. + If the component is being animated, this will return the target position that + was specified when animateComponent() was called. - The size of each dimension of the array will be getKernelSize(). + If the specified component isn't currently being animated, this method will just + return its current position. */ - float** getValues() const throw() { return values; } - - /** Applies the kernel to an image. + const Rectangle getComponentDestination (Component* const component); - @param destImage the image that will receive the resultant convoluted pixels. - @param sourceImage an optional source image to read from - if this is 0, then the - destination image will be used as the source. If an image is - specified, it must be exactly the same size and type as the destination - image. - @param x the region of the image to apply the filter to - @param y the region of the image to apply the filter to - @param width the region of the image to apply the filter to - @param height the region of the image to apply the filter to + /** Returns true if the specified component is currently being animated. */ - void applyToImage (Image& destImage, - const Image* sourceImage, - int x, - int y, - int width, - int height) const; + bool isAnimating (Component* component) const; juce_UseDebuggingNewOperator private: - float** values; - int size; + VoidArray tasks; + uint32 lastTime; - // no reason not to implement these one day.. - ImageConvolutionKernel (const ImageConvolutionKernel&); - const ImageConvolutionKernel& operator= (const ImageConvolutionKernel&); + void* findTaskFor (Component* const component) const; + void timerCallback(); }; -#endif // __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ -/********* End of inlined file: juce_ImageConvolutionKernel.h *********/ - -#endif -#ifndef __JUCE_DRAWABLE_JUCEHEADER__ +#endif // __JUCE_COMPONENTANIMATOR_JUCEHEADER__ +/********* End of inlined file: juce_ComponentAnimator.h *********/ -/********* Start of inlined file: juce_Drawable.h *********/ -#ifndef __JUCE_DRAWABLE_JUCEHEADER__ -#define __JUCE_DRAWABLE_JUCEHEADER__ +class ToolbarItemComponent; +class ToolbarItemFactory; +class MissingItemsComponent; /** - The base class for objects which can draw themselves, e.g. polygons, images, etc. + A toolbar component. - @see DrawableComposite, DrawableImage, DrawablePath, DrawableText + A toolbar contains a horizontal or vertical strip of ToolbarItemComponents, + and looks after their order and layout. + + Items (icon buttons or other custom components) are added to a toolbar using a + ToolbarItemFactory - each type of item is given a unique ID number, and a + toolbar might contain more than one instance of a particular item type. + + Toolbars can be interactively customised, allowing the user to drag the items + around, and to drag items onto or off the toolbar, using the ToolbarItemPalette + component as a source of new items. + + @see ToolbarItemFactory, ToolbarItemComponent, ToolbarItemPalette */ -class JUCE_API Drawable +class JUCE_API Toolbar : public Component, + public DragAndDropContainer, + public DragAndDropTarget, + private ButtonListener { -protected: +public: - /** The base class can't be instantiated directly. + /** Creates an empty toolbar component. - @see DrawableComposite, DrawableImage, DrawablePath, DrawableText + To add some icons or other components to your toolbar, you'll need to + create a ToolbarItemFactory class that can create a suitable set of + ToolbarItemComponents. + + @see ToolbarItemFactory, ToolbarItemComponents */ - Drawable(); + Toolbar(); -public: - /** Destructor. */ - virtual ~Drawable(); + /** Destructor. - /** Creates a deep copy of this Drawable object. + Any items on the bar will be deleted when the toolbar is deleted. + */ + ~Toolbar(); - Use this to create a new copy of this and any sub-objects in the tree. + /** Changes the bar's orientation. + @see isVertical */ - virtual Drawable* createCopy() const = 0; + void setVertical (const bool shouldBeVertical); - /** Renders this Drawable object. - @see drawWithin + /** Returns true if the bar is set to be vertical, or false if it's horizontal. + + You can change the bar's orientation with setVertical(). */ - void draw (Graphics& g, const float opacity, - const AffineTransform& transform = AffineTransform::identity) const; + bool isVertical() const throw() { return vertical; } - /** Renders the Drawable at a given offset within the Graphics context. + /** Returns the depth of the bar. - The co-ordinates passed-in are used to translate the object relative to its own - origin before drawing it - this is basically a quick way of saying: + If the bar is horizontal, this will return its height; if it's vertical, it + will return its width. - @code - draw (g, AffineTransform::translation (x, y)). - @endcode + @see getLength */ - void drawAt (Graphics& g, - const float x, - const float y, - const float opacity) const; + int getThickness() const throw(); - /** Renders the Drawable within a rectangle, scaling it to fit neatly inside without - changing its aspect-ratio. + /** Returns the length of the bar. - The object can placed arbitrarily within the rectangle based on a Justification type, - and can either be made as big as possible, or just reduced to fit. + If the bar is horizontal, this will return its width; if it's vertical, it + will return its height. - @param g the graphics context to render onto - @param destX top-left of the target rectangle to fit it into - @param destY top-left of the target rectangle to fit it into - @param destWidth size of the target rectangle to fit the image into - @param destHeight size of the target rectangle to fit the image into - @param placement defines the alignment and rescaling to use to fit - this object within the target rectangle. - @param opacity the opacity to use, in the range 0 to 1.0 + @see getThickness */ - void drawWithin (Graphics& g, - const int destX, - const int destY, - const int destWidth, - const int destHeight, - const RectanglePlacement& placement, - const float opacity) const; + int getLength() const throw(); - /** Holds the information needed when telling a drawable to render itself. - @see Drawable::draw + /** Deletes all items from the bar. */ - class RenderingContext - { - public: - RenderingContext (Graphics& g, const AffineTransform& transform, const float opacity) throw(); + void clear(); - Graphics& g; - AffineTransform transform; - float opacity; + /** Adds an item to the toolbar. - private: - const RenderingContext& operator= (const RenderingContext&); - }; + The factory's ToolbarItemFactory::createItem() will be called by this method + to create the component that will actually be added to the bar. - /** Renders this Drawable object. - @see draw - */ - virtual void render (const RenderingContext& context) const = 0; + The new item will be inserted at the specified index (if the index is -1, it + will be added to the right-hand or bottom end of the bar). - /** Returns the smallest rectangle that can contain this Drawable object. + Once added, the component will be automatically deleted by this object when it + is no longer needed. - Co-ordinates are relative to the object's own origin. + @see ToolbarItemFactory */ - virtual void getBounds (float& x, float& y, float& width, float& height) const = 0; - - /** Returns true if the given point is somewhere inside this Drawable. + void addItem (ToolbarItemFactory& factory, + const int itemId, + const int insertIndex = -1); - Co-ordinates are relative to the object's own origin. + /** Deletes one of the items from the bar. */ - virtual bool hitTest (float x, float y) const = 0; + void removeToolbarItem (const int itemIndex); - /** Returns the name given to this drawable. - @see setName + /** Returns the number of items currently on the toolbar. + + @see getItemId, getItemComponent */ - const String& getName() const throw() { return name; } + int getNumItems() const throw(); - /** Assigns a name to this drawable. */ - void setName (const String& newName) throw() { name = newName; } + /** Returns the ID of the item with the given index. - /** Tries to turn some kind of image file into a drawable. + If the index is less than zero or greater than the number of items, + this will return 0. - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. + @see getNumItems */ - static Drawable* createFromImageData (const void* data, const int numBytes); - - /** Tries to turn a stream containing some kind of image data into a drawable. + int getItemId (const int itemIndex) const throw(); - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. - */ - static Drawable* createFromImageDataStream (InputStream& dataSource); + /** Returns the component being used for the item with the given index. - /** Tries to turn a file containing some kind of image data into a drawable. + If the index is less than zero or greater than the number of items, + this will return 0. - The data could be an image that the ImageFileFormat class understands, or it - could be SVG. + @see getNumItems */ - static Drawable* createFromImageFile (const File& file); - - /** Attempts to parse an SVG (Scalable Vector Graphics) document, and to turn this - into a Drawable tree. + ToolbarItemComponent* getItemComponent (const int itemIndex) const throw(); - The object returned must be deleted by the caller. If something goes wrong - while parsing, it may return 0. + /** Clears this toolbar and adds to it the default set of items that the specified + factory creates. - SVG is a pretty large and complex spec, and this doesn't aim to be a full - implementation, but it can return the basic vector objects. + @see ToolbarItemFactory::getDefaultItemSet */ - static Drawable* createFromSVG (const XmlElement& svgDocument); + void addDefaultItems (ToolbarItemFactory& factoryToUse); - /** Tries to create a Drawable from a previously-saved ValueTree. - The ValueTree must have been created by the createValueTree() method. + /** Options for the way items should be displayed. + @see setStyle, getStyle */ - static Drawable* createFromValueTree (const ValueTree& tree) throw(); + enum ToolbarItemStyle + { + iconsOnly, /**< Means that the toolbar should just contain icons. */ + iconsWithText, /**< Means that the toolbar should have text labels under each icon. */ + textOnly /**< Means that the toolbar only display text labels for each item. */ + }; - /** Creates a ValueTree to represent this Drawable. - The VarTree that is returned can be turned back into a Drawable with - createFromValueTree(). + /** Returns the toolbar's current style. + @see ToolbarItemStyle, setStyle */ - virtual ValueTree createValueTree() const throw() = 0; - - juce_UseDebuggingNewOperator + ToolbarItemStyle getStyle() const throw() { return toolbarStyle; } -private: - Drawable (const Drawable&); - const Drawable& operator= (const Drawable&); + /** Changes the toolbar's current style. + @see ToolbarItemStyle, getStyle, ToolbarItemComponent::setStyle + */ + void setStyle (const ToolbarItemStyle& newStyle); - String name; -}; + /** Flags used by the showCustomisationDialog() method. */ + enum CustomisationFlags + { + allowIconsOnlyChoice = 1, /**< If this flag is specified, the customisation dialog can + show the "icons only" option on its choice of toolbar styles. */ + allowIconsWithTextChoice = 2, /**< If this flag is specified, the customisation dialog can + show the "icons with text" option on its choice of toolbar styles. */ + allowTextOnlyChoice = 4, /**< If this flag is specified, the customisation dialog can + show the "text only" option on its choice of toolbar styles. */ + showResetToDefaultsButton = 8, /**< If this flag is specified, the customisation dialog can + show a button to reset the toolbar to its default set of items. */ -#endif // __JUCE_DRAWABLE_JUCEHEADER__ -/********* End of inlined file: juce_Drawable.h *********/ + allCustomisationOptionsEnabled = (allowIconsOnlyChoice | allowIconsWithTextChoice | allowTextOnlyChoice | showResetToDefaultsButton) + }; -#endif -#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ + /** Pops up a modal dialog box that allows this toolbar to be customised by the user. -/********* Start of inlined file: juce_DrawableComposite.h *********/ -#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ -#define __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ + The dialog contains a ToolbarItemPalette and various controls for editing other + aspects of the toolbar. This method will block and run the dialog box modally, + returning when the user closes it. -/** - A drawable object which acts as a container for a set of other Drawables. + The factory is used to determine the set of items that will be shown on the + palette. - @see Drawable -*/ -class JUCE_API DrawableComposite : public Drawable -{ -public: + The optionFlags parameter is a bitwise-or of values from the CustomisationFlags + enum. - /** Creates a composite Drawable. + @see ToolbarItemPalette */ - DrawableComposite(); - - /** Destructor. */ - virtual ~DrawableComposite(); + void showCustomisationDialog (ToolbarItemFactory& factory, + const int optionFlags = allCustomisationOptionsEnabled); - /** Adds a new sub-drawable to this one. + /** Turns on or off the toolbar's editing mode, in which its items can be + rearranged by the user. - This passes in a Drawable pointer for this object to look after. To add a copy - of a drawable, use the form of this method that takes a Drawable reference instead. + (In most cases it's easier just to use showCustomisationDialog() instead of + trying to enable editing directly). - @param drawable the object to add - this will be deleted automatically - when no longer needed, so the caller mustn't keep any - pointers to it. - @param transform the transform to apply to this drawable when it's being - drawn - @param index where to insert it in the list of drawables. 0 is the back, - -1 is the front, or any value from 0 and getNumDrawables() - can be used - @see removeDrawable + @see ToolbarItemPalette */ - void insertDrawable (Drawable* drawable, - const AffineTransform& transform = AffineTransform::identity, - const int index = -1); - - /** Adds a new sub-drawable to this one. - - This takes a copy of a Drawable and adds it to this object. To pass in a Drawable - for this object to look after, use the form of this method that takes a Drawable - pointer instead. + void setEditingActive (const bool editingEnabled); - @param drawable the object to add - an internal copy will be made of this object - @param transform the transform to apply to this drawable when it's being - drawn - @param index where to insert it in the list of drawables. 0 is the back, - -1 is the front, or any value from 0 and getNumDrawables() - can be used - @see removeDrawable - */ - void insertDrawable (const Drawable& drawable, - const AffineTransform& transform = AffineTransform::identity, - const int index = -1); + /** A set of colour IDs to use to change the colour of various aspects of the toolbar. - /** Deletes one of the Drawable objects. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - @param index the index of the drawable to delete, between 0 - and (getNumDrawables() - 1). - @param deleteDrawable if this is true, the drawable that is removed will also - be deleted. If false, it'll just be removed. - @see insertDrawable, getNumDrawables + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void removeDrawable (const int index, const bool deleteDrawable = true); + enum ColourIds + { + backgroundColourId = 0x1003200, /**< A colour to use to fill the toolbar's background. For + more control over this, override LookAndFeel::paintToolbarBackground(). */ + separatorColourId = 0x1003210, /**< A colour to use to draw the separator lines. */ - /** Returns the number of drawables contained inside this one. + buttonMouseOverBackgroundColourId = 0x1003220, /**< A colour used to paint the background of buttons when the mouse is + over them. */ + buttonMouseDownBackgroundColourId = 0x1003230, /**< A colour used to paint the background of buttons when the mouse is + held down on them. */ - @see getDrawable - */ - int getNumDrawables() const throw() { return drawables.size(); } + labelTextColourId = 0x1003240, /**< A colour to use for drawing the text under buttons + when the style is set to iconsWithText or textOnly. */ - /** Returns one of the drawables that are contained in this one. + editingModeOutlineColourId = 0x1003250 /**< A colour to use for an outline around buttons when + the customisation dialog is active and the mouse moves over them. */ + }; - Each drawable also has a transform associated with it - you can use getDrawableTransform() - to find it. + /** Returns a string that represents the toolbar's current set of items. - The pointer returned is managed by this object and will be deleted when no longer - needed, so be careful what you do with it. + This lets you later restore the same item layout using restoreFromString(). - @see getNumDrawables + @see restoreFromString */ - Drawable* getDrawable (const int index) const throw() { return drawables [index]; } - - /** Returns the transform that applies to one of the drawables that are contained in this one. - - The pointer returned is managed by this object and will be deleted when no longer - needed, so be careful what you do with it. + const String toString() const; - @see getNumDrawables - */ - const AffineTransform* getDrawableTransform (const int index) const throw() { return transforms [index]; } + /** Restores a set of items that was previously stored in a string by the toString() + method. - /** Brings one of the Drawables to the front. + The factory object is used to create any item components that are needed. - @param index the index of the drawable to move, between 0 - and (getNumDrawables() - 1). - @see insertDrawable, getNumDrawables + @see toString */ - void bringToFront (const int index); + bool restoreFromString (ToolbarItemFactory& factoryToUse, + const String& savedVersion); /** @internal */ - void render (const Drawable::RenderingContext& context) const; + void paint (Graphics& g); /** @internal */ - void getBounds (float& x, float& y, float& width, float& height) const; + void resized(); /** @internal */ - bool hitTest (float x, float y) const; + void buttonClicked (Button*); /** @internal */ - Drawable* createCopy() const; + void mouseDown (const MouseEvent&); /** @internal */ - ValueTree createValueTree() const throw(); + bool isInterestedInDragSource (const String&, Component*); /** @internal */ - static DrawableComposite* createFromValueTree (const ValueTree& tree) throw(); + void itemDragMove (const String&, Component*, int, int); + /** @internal */ + void itemDragExit (const String&, Component*); + /** @internal */ + void itemDropped (const String&, Component*, int, int); + /** @internal */ + void updateAllItemPositions (const bool animate); + /** @internal */ + static ToolbarItemComponent* createItem (ToolbarItemFactory&, const int itemId); juce_UseDebuggingNewOperator private: - OwnedArray drawables; - OwnedArray transforms; + Button* missingItemsButton; + bool vertical, isEditingActive; + ToolbarItemStyle toolbarStyle; + ComponentAnimator animator; + friend class MissingItemsComponent; + Array items; - DrawableComposite (const DrawableComposite&); - const DrawableComposite& operator= (const DrawableComposite&); -}; + friend class ItemDragAndDropOverlayComponent; + static const tchar* const toolbarDragDescriptor; -#endif // __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ -/********* End of inlined file: juce_DrawableComposite.h *********/ + void addItemInternal (ToolbarItemFactory& factory, const int itemId, const int insertIndex); -#endif -#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ + ToolbarItemComponent* getNextActiveComponent (int index, const int delta) const; -/********* Start of inlined file: juce_DrawableImage.h *********/ -#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ -#define __JUCE_DRAWABLEIMAGE_JUCEHEADER__ + Toolbar (const Toolbar&); + const Toolbar& operator= (const Toolbar&); +}; + +#endif // __JUCE_TOOLBAR_JUCEHEADER__ +/********* End of inlined file: juce_Toolbar.h *********/ + +class ItemDragAndDropOverlayComponent; /** - A drawable object which is a bitmap image. + A component that can be used as one of the items in a Toolbar. - @see Drawable + Each of the items on a toolbar must be a component derived from ToolbarItemComponent, + and these objects are always created by a ToolbarItemFactory - see the ToolbarItemFactory + class for further info about creating them. + + The ToolbarItemComponent class is actually a button, but can be used to hold non-button + components too. To do this, set the value of isBeingUsedAsAButton to false when + calling the constructor, and override contentAreaChanged(), in which you can position + any sub-components you need to add. + + To add basic buttons without writing a special subclass, have a look at the + ToolbarButton class. + + @see ToolbarButton, Toolbar, ToolbarItemFactory */ -class JUCE_API DrawableImage : public Drawable +class JUCE_API ToolbarItemComponent : public Button { public: - DrawableImage(); + /** Constructor. - /** Destructor. */ - virtual ~DrawableImage(); + @param itemId the ID of the type of toolbar item which this represents + @param labelText the text to display if the toolbar's style is set to + Toolbar::iconsWithText or Toolbar::textOnly + @param isBeingUsedAsAButton set this to false if you don't want the button + to draw itself with button over/down states when the mouse + moves over it or clicks + */ + ToolbarItemComponent (const int itemId, + const String& labelText, + const bool isBeingUsedAsAButton); - /** Sets the image that this drawable will render. + /** Destructor. */ + ~ToolbarItemComponent(); - An internal copy is made of the image passed-in. If you want to provide an - image that this object can take charge of without needing to create a copy, - use the other setImage() method. + /** Returns the item type ID that this component represents. + This value is in the constructor. */ - void setImage (const Image& imageToCopy); + int getItemId() const throw() { return itemId; } - /** Sets the image that this drawable will render. + /** Returns the toolbar that contains this component, or 0 if it's not currently + inside one. + */ + Toolbar* getToolbar() const; - An internal copy of this will not be made, so the caller mustn't delete - the image while it's still being used by this object. + /** Returns true if this component is currently inside a toolbar which is vertical. + @see Toolbar::isVertical + */ + bool isToolbarVertical() const; - A good way to use this is with the ImageCache - if you create an image - with ImageCache and pass it in here with releaseWhenNotNeeded = true, then - it'll be released neatly with its reference count being decreased. + /** Returns the current style setting of this item. - @param imageToUse the image to render - @param releaseWhenNotNeeded if false, a simple pointer is kept to the image; if true, - then the image will be deleted when this object no longer - needs it - unless the image was created by the ImageCache, - in which case it will be released with ImageCache::release(). + Styles are listed in the Toolbar::ToolbarItemStyle enum. + @see setStyle, Toolbar::getStyle */ - void setImage (Image* imageToUse, - const bool releaseWhenNotNeeded); - - /** Returns the current image. */ - Image* getImage() const throw() { return image; } + Toolbar::ToolbarItemStyle getStyle() const throw() { return toolbarStyle; } - /** Clears (and possibly deletes) the currently set image. */ - void clearImage(); + /** Changes the current style setting of this item. - /** Sets the opacity to use when drawing the image. */ - void setOpacity (const float newOpacity); + Styles are listed in the Toolbar::ToolbarItemStyle enum, and are automatically updated + by the toolbar that holds this item. - /** Returns the image's opacity. */ - float getOpacity() const throw() { return opacity; } + @see setStyle, Toolbar::setStyle + */ + virtual void setStyle (const Toolbar::ToolbarItemStyle& newStyle); - /** Sets a colour to draw over the image's alpha channel. + /** Returns the area of the component that should be used to display the button image or + other contents of the item. - By default this is transparent so isn't drawn, but if you set a non-transparent - colour here, then it will be overlaid on the image, using the image's alpha - channel as a mask. + This content area may change when the item's style changes, and may leave a space around the + edge of the component where the text label can be shown. - This is handy for doing things like darkening or lightening an image by overlaying - it with semi-transparent black or white. + @see contentAreaChanged */ - void setOverlayColour (const Colour& newOverlayColour); - - /** Returns the overlay colour. */ - const Colour& getOverlayColour() const throw() { return overlayColour; } + const Rectangle getContentArea() const throw() { return contentArea; } - /** @internal */ - void render (const Drawable::RenderingContext& context) const; - /** @internal */ - void getBounds (float& x, float& y, float& width, float& height) const; - /** @internal */ - bool hitTest (float x, float y) const; - /** @internal */ - Drawable* createCopy() const; - /** @internal */ - ValueTree createValueTree() const throw(); - /** @internal */ - static DrawableImage* createFromValueTree (const ValueTree& tree) throw(); + /** This method must return the size criteria for this item, based on a given toolbar + size and orientation. - juce_UseDebuggingNewOperator + The preferredSize, minSize and maxSize values must all be set by your implementation + method. If the toolbar is horizontal, these will be the width of the item; for a vertical + toolbar, they refer to the item's height. -private: - Image* image; - bool canDeleteImage; - float opacity; - Colour overlayColour; + The preferredSize is the size that the component would like to be, and this must be + between the min and max sizes. For a fixed-size item, simply set all three variables to + the same value. - DrawableImage (const DrawableImage&); - const DrawableImage& operator= (const DrawableImage&); -}; + The toolbarThickness parameter tells you the depth of the toolbar - the same as calling + Toolbar::getThickness(). -#endif // __JUCE_DRAWABLEIMAGE_JUCEHEADER__ -/********* End of inlined file: juce_DrawableImage.h *********/ + The isToolbarVertical parameter tells you whether the bar is oriented horizontally or + vertically. + */ + virtual bool getToolbarItemSizes (int toolbarThickness, + bool isToolbarVertical, + int& preferredSize, + int& minSize, + int& maxSize) = 0; -#endif -#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ + /** Your subclass should use this method to draw its content area. -/********* Start of inlined file: juce_DrawableText.h *********/ -#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ -#define __JUCE_DRAWABLETEXT_JUCEHEADER__ + The graphics object that is passed-in will have been clipped and had its origin + moved to fit the content area as specified get getContentArea(). The width and height + parameters are the width and height of the content area. -/** - A drawable object which renders a line of text. + If the component you're writing isn't a button, you can just do nothing in this method. + */ + virtual void paintButtonArea (Graphics& g, + int width, int height, + bool isMouseOver, bool isMouseDown) = 0; - @see Drawable -*/ -class JUCE_API DrawableText : public Drawable -{ -public: + /** Callback to indicate that the content area of this item has changed. - /** Creates a DrawableText object. */ - DrawableText(); + This might be because the component was resized, or because the style changed and + the space needed for the text label is different. - /** Destructor. */ - virtual ~DrawableText(); + See getContentArea() for a description of what the area is. + */ + virtual void contentAreaChanged (const Rectangle& newBounds) = 0; - /** Sets the block of text to render */ - void setText (const GlyphArrangement& newText); + /** Editing modes. + These are used by setEditingMode(), but will be rarely needed in user code. + */ + enum ToolbarEditingMode + { + normalMode = 0, /**< Means that the component is active, inside a toolbar. */ + editableOnToolbar, /**< Means that the component is on a toolbar, but the toolbar is in + customisation mode, and the items can be dragged around. */ + editableOnPalette /**< Means that the component is on an new-item palette, so it can be + dragged onto a toolbar to add it to that bar.*/ + }; - /** Sets a single line of text to render. + /** Changes the editing mode of this component. - This is a convenient method of adding a single line - for - more complex text, use the setText() that takes a - GlyphArrangement instead. + This is used by the ToolbarItemPalette and related classes for making the items draggable, + and is unlikely to be of much use in end-user-code. */ - void setText (const String& newText, const Font& fontToUse); - - /** Returns the text arrangement that was set with setText(). */ - const GlyphArrangement& getText() const throw() { return text; } + void setEditingMode (const ToolbarEditingMode newMode); - /** Sets the colour of the text. */ - void setColour (const Colour& newColour); + /** Returns the current editing mode of this component. - /** Returns the current text colour. */ - const Colour& getColour() const throw() { return colour; } + This is used by the ToolbarItemPalette and related classes for making the items draggable, + and is unlikely to be of much use in end-user-code. + */ + ToolbarEditingMode getEditingMode() const throw() { return mode; } /** @internal */ - void render (const Drawable::RenderingContext& context) const; - /** @internal */ - void getBounds (float& x, float& y, float& width, float& height) const; - /** @internal */ - bool hitTest (float x, float y) const; - /** @internal */ - Drawable* createCopy() const; - /** @internal */ - ValueTree createValueTree() const throw(); + void paintButton (Graphics& g, bool isMouseOver, bool isMouseDown); /** @internal */ - static DrawableText* createFromValueTree (const ValueTree& tree) throw(); + void resized(); juce_UseDebuggingNewOperator private: - GlyphArrangement text; - Colour colour; + friend class Toolbar; + friend class ItemDragAndDropOverlayComponent; + const int itemId; + ToolbarEditingMode mode; + Toolbar::ToolbarItemStyle toolbarStyle; + Component* overlayComp; + int dragOffsetX, dragOffsetY; + bool isActive, isBeingDragged, isBeingUsedAsAButton; + Rectangle contentArea; - DrawableText (const DrawableText&); - const DrawableText& operator= (const DrawableText&); + ToolbarItemComponent (const ToolbarItemComponent&); + const ToolbarItemComponent& operator= (const ToolbarItemComponent&); }; -#endif // __JUCE_DRAWABLETEXT_JUCEHEADER__ -/********* End of inlined file: juce_DrawableText.h *********/ - -#endif -#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ - -/********* Start of inlined file: juce_DrawablePath.h *********/ -#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ -#define __JUCE_DRAWABLEPATH_JUCEHEADER__ +#endif // __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ToolbarItemComponent.h *********/ /** - A drawable object which renders a filled or outlined shape. + A type of button designed to go on a toolbar. - @see Drawable + This simple button can have two Drawable objects specified - one for normal + use and another one (optionally) for the button's "on" state if it's a + toggle button. + + @see Toolbar, ToolbarItemFactory, ToolbarItemComponent, Drawable, Button */ -class JUCE_API DrawablePath : public Drawable +class JUCE_API ToolbarButton : public ToolbarItemComponent { public: - /** Creates a DrawablePath. + /** Creates a ToolbarButton. + + @param itemId the ID for this toolbar item type. This is passed through to the + ToolbarItemComponent constructor + @param labelText the text to display on the button (if the toolbar is using a style + that shows text labels). This is passed through to the + ToolbarItemComponent constructor + @param normalImage a drawable object that the button should use as its icon. The object + that is passed-in here will be kept by this object and will be + deleted when no longer needed or when this button is deleted. + @param toggledOnImage a drawable object that the button can use as its icon if the button + is in a toggled-on state (see the Button::getToggleState() method). If + 0 is passed-in here, then the normal image will be used instead, regardless + of the toggle state. The object that is passed-in here will be kept by + this object and will be deleted when no longer needed or when this button + is deleted. */ - DrawablePath(); + ToolbarButton (const int itemId, + const String& labelText, + Drawable* const normalImage, + Drawable* const toggledOnImage); /** Destructor. */ - virtual ~DrawablePath(); - - /** Changes the path that will be drawn. + ~ToolbarButton(); - @see setFillColour, setStrokeType - */ - void setPath (const Path& newPath) throw(); + /** @internal */ + bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, + int& minSize, int& maxSize); + /** @internal */ + void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown); + /** @internal */ + void contentAreaChanged (const Rectangle& newBounds); - /** Returns the current path. */ - const Path& getPath() const throw() { return path; } - - /** Sets a fill type for the path. - - This colour is used to fill the path - if you don't want the path to be - filled (e.g. if you're just drawing an outline), set this to a transparent - colour. - - @see setPath, setStrokeFill - */ - void setFill (const FillType& newFill) throw(); - - /** Returns the current fill type. - @see setFill - */ - const FillType& getFill() const throw() { return mainFill; } - - /** Sets the fill type with which the outline will be drawn. - @see setFill - */ - void setStrokeFill (const FillType& newStrokeFill) throw(); - - /** Returns the current stroke fill. - @see setStrokeFill - */ - const FillType& getStrokeFill() const throw() { return strokeFill; } - - /** Changes the properties of the outline that will be drawn around the path. - If the stroke has 0 thickness, no stroke will be drawn. - @see setStrokeThickness, setStrokeColour - */ - void setStrokeType (const PathStrokeType& newStrokeType) throw(); - - /** Changes the stroke thickness. - This is a shortcut for calling setStrokeType. - */ - void setStrokeThickness (const float newThickness) throw(); - - /** Returns the current outline style. */ - const PathStrokeType& getStrokeType() const throw() { return strokeType; } - - /** @internal */ - void render (const Drawable::RenderingContext& context) const; - /** @internal */ - void getBounds (float& x, float& y, float& width, float& height) const; - /** @internal */ - bool hitTest (float x, float y) const; - /** @internal */ - Drawable* createCopy() const; - /** @internal */ - ValueTree createValueTree() const throw(); - /** @internal */ - static DrawablePath* createFromValueTree (const ValueTree& tree) throw(); - - juce_UseDebuggingNewOperator + juce_UseDebuggingNewOperator private: - Path path, stroke; - FillType mainFill, strokeFill; - PathStrokeType strokeType; - - void updateOutline(); + Drawable* const normalImage; + Drawable* const toggledOnImage; - DrawablePath (const DrawablePath&); - const DrawablePath& operator= (const DrawablePath&); + ToolbarButton (const ToolbarButton&); + const ToolbarButton& operator= (const ToolbarButton&); }; -#endif // __JUCE_DRAWABLEPATH_JUCEHEADER__ -/********* End of inlined file: juce_DrawablePath.h *********/ - -#endif -#ifndef __JUCE_COMPONENT_JUCEHEADER__ - -#endif -#ifndef __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ - -#endif -#ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__ - -#endif -#ifndef __JUCE_DESKTOP_JUCEHEADER__ +#endif // __JUCE_TOOLBARBUTTON_JUCEHEADER__ +/********* End of inlined file: juce_ToolbarButton.h *********/ #endif -#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ +#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ -/********* Start of inlined file: juce_ArrowButton.h *********/ -#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ -#define __JUCE_ARROWBUTTON_JUCEHEADER__ +/********* Start of inlined file: juce_CodeDocument.h *********/ +#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ +#define __JUCE_CODEDOCUMENT_JUCEHEADER__ -/********* Start of inlined file: juce_DropShadowEffect.h *********/ -#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ -#define __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ +class CodeDocumentLine; /** - An effect filter that adds a drop-shadow behind the image's content. - - (This will only work on images/components that aren't opaque, of course). + A class for storing and manipulating a source code file. - When added to a component, this effect will draw a soft-edged - shadow based on what gets drawn inside it. The shadow will also - be applied to the component's children. + When using a CodeEditorComponent, it takes one of these as its source object. - For speed, this doesn't use a proper gaussian blur, but cheats by - using a simple bilinear filter. If you need a really high-quality - shadow, check out ImageConvolutionKernel::createGaussianBlur() + The CodeDocument stores its content as an array of lines, which makes it + quick to insert and delete. - @see Component::setComponentEffect + @see CodeEditorComponent */ -class JUCE_API DropShadowEffect : public ImageEffectFilter +class JUCE_API CodeDocument { public: - - /** Creates a default drop-shadow effect. - - To customise the shadow's appearance, use the setShadowProperties() - method. + /** Creates a new, empty document. */ - DropShadowEffect(); + CodeDocument(); /** Destructor. */ - ~DropShadowEffect(); + ~CodeDocument(); - /** Sets up parameters affecting the shadow's appearance. + /** A position in a code document. - @param newRadius the (approximate) radius of the blur used - @param newOpacity the opacity with which the shadow is rendered - @param newShadowOffsetX allows the shadow to be shifted in relation to the - component's contents - @param newShadowOffsetY allows the shadow to be shifted in relation to the - component's contents + Using this class you can find a position in a code document and quickly get its + character position, line, and index. By calling setPositionMaintained (true), the + position is automatically updated when text is inserted or deleted in the document, + so that it maintains its original place in the text. */ - void setShadowProperties (const float newRadius, - const float newOpacity, - const int newShadowOffsetX, - const int newShadowOffsetY); + class JUCE_API Position + { + public: + /** Creates an uninitialised postion. + Don't attempt to call any methods on this until you've given it an owner document + to refer to! + */ + Position() throw(); - /** @internal */ - void applyEffect (Image& sourceImage, Graphics& destContext); + /** Creates a position based on a line and index in a document. - juce_UseDebuggingNewOperator + Note that this index is NOT the column number, it's the number of characters from the + start of the line. The "column" number isn't quite the same, because if the line + contains any tab characters, the relationship of the index to its visual column depends on + the number of spaces per tab being used! -private: - int offsetX, offsetY; - float radius, opacity; -}; + Lines are numbered from zero, and if the line or index are beyond the bounds of the document, + they will be adjusted to keep them within its limits. + */ + Position (const CodeDocument* const ownerDocument, + const int line, const int indexInLine) throw(); -#endif // __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ -/********* End of inlined file: juce_DropShadowEffect.h *********/ + /** Creates a position based on a character index in a document. + This position is placed at the specified number of characters from the start of the + document. The line and column are auto-calculated. -/** - A button with an arrow in it. + If the position is beyond the range of the document, it'll be adjusted to keep it + inside. + */ + Position (const CodeDocument* const ownerDocument, + const int charactersFromStartOfDocument) throw(); - @see Button -*/ -class JUCE_API ArrowButton : public Button -{ -public: + /** Creates a copy of another position. - /** Creates an ArrowButton. + This will copy the position, but the new object will not be set to maintain its position, + even if the source object was set to do so. + */ + Position (const Position& other) throw(); - @param buttonName the name to give the button - @param arrowDirection the direction the arrow should point in, where 0.0 is - pointing right, 0.25 is down, 0.5 is left, 0.75 is up - @param arrowColour the colour to use for the arrow - */ - ArrowButton (const String& buttonName, - float arrowDirection, - const Colour& arrowColour); + /** Destructor. */ + ~Position() throw(); - /** Destructor. */ - ~ArrowButton(); + const Position& operator= (const Position& other) throw(); + bool operator== (const Position& other) const throw(); + bool operator!= (const Position& other) const throw(); - juce_UseDebuggingNewOperator + /** Points this object at a new position within the document. -protected: - /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); + If the position is beyond the range of the document, it'll be adjusted to keep it + inside. + @see getPosition, setLineAndIndex + */ + void setPosition (const int charactersFromStartOfDocument) throw(); - /** @internal */ - void buttonStateChanged(); + /** Returns the position as the number of characters from the start of the document. + @see setPosition, getLineNumber, getIndexInLine + */ + int getPosition() const throw() { return characterPos; } -private: + /** Moves the position to a new line and index within the line. - Colour colour; - DropShadowEffect shadow; - Path path; - int offset; + Note that the index is NOT the column at which the position appears in an editor. + If the line contains any tab characters, the relationship of the index to its + visual position depends on the number of spaces per tab being used! - ArrowButton (const ArrowButton&); - const ArrowButton& operator= (const ArrowButton&); -}; + Lines are numbered from zero, and if the line or index are beyond the bounds of the document, + they will be adjusted to keep them within its limits. + */ + void setLineAndIndex (const int newLine, const int newIndexInLine) throw(); -#endif // __JUCE_ARROWBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_ArrowButton.h *********/ + /** Returns the line number of this position. + The first line in the document is numbered zero, not one! + */ + int getLineNumber() const throw() { return line; } -#endif -#ifndef __JUCE_BUTTON_JUCEHEADER__ + /** Returns the number of characters from the start of the line. -#endif -#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ + Note that this value is NOT the column at which the position appears in an editor. + If the line contains any tab characters, the relationship of the index to its + visual position depends on the number of spaces per tab being used! + */ + int getIndexInLine() const throw() { return indexInLine; } -/********* Start of inlined file: juce_DrawableButton.h *********/ -#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ -#define __JUCE_DRAWABLEBUTTON_JUCEHEADER__ + /** Allows the position to be automatically updated when the document changes. -/** - A button that displays a Drawable. + If this is set to true, the positon will register with its document so that + when the document has text inserted or deleted, this position will be automatically + moved to keep it at the same position in the text. + */ + void setPositionMaintained (const bool isMaintained) throw(); - Up to three Drawable objects can be given to this button, to represent the - 'normal', 'over' and 'down' states. + /** Moves the position forwards or backwards by the specified number of characters. + @see movedBy + */ + void moveBy (int characterDelta) throw(); - @see Button -*/ -class JUCE_API DrawableButton : public Button -{ -public: + /** Returns a position which is the same as this one, moved by the specified number of + characters. + @see moveBy + */ + const Position movedBy (const int characterDelta) const throw(); - enum ButtonStyle - { - ImageFitted, /**< The button will just display the images, but will resize and centre them to fit inside it. */ - ImageRaw, /**< The button will just display the images in their normal size and position. - This leaves it up to the caller to make sure the images are the correct size and position for the button. */ - ImageAboveTextLabel, /**< Draws the button as a text label across the bottom with the image resized and scaled to fit above it. */ - ImageOnButtonBackground /**< Draws the button as a standard rounded-rectangle button with the image on top. */ + /** Returns a position which is the same as this one, moved up or down by the specified + number of lines. + @see movedBy + */ + const Position movedByLines (const int deltaLines) const throw(); + + /** Returns the character in the document at this position. + @see getLineText + */ + const tchar getCharacter() const throw(); + + /** Returns the line from the document that this position is within. + @see getCharacter, getLineNumber + */ + const String getLineText() const throw(); + + private: + CodeDocument* owner; + int characterPos, line, indexInLine; + bool positionMaintained; }; - /** Creates a DrawableButton. + /** Returns the full text of the document. */ + const String getAllContent() const throw(); - After creating one of these, use setImages() to specify the drawables to use. + /** Returns a section of the document's text. */ + const String getTextBetween (const Position& start, const Position& end) const throw(); - @param buttonName the name to give the component - @param buttonStyle the layout to use + /** Returns a line from the document. */ + const String getLine (const int lineIndex) const throw(); - @see ButtonStyle, setButtonStyle, setImages - */ - DrawableButton (const String& buttonName, - const ButtonStyle buttonStyle); + /** Returns the number of characters in the document. */ + int getNumCharacters() const throw(); - /** Destructor. */ - ~DrawableButton(); + /** Returns the number of lines in the document. */ + int getNumLines() const throw() { return lines.size(); } - /** Sets up the images to draw for the various button states. + /** Returns the number of characters in the longest line of the document. */ + int getMaximumLineLength() throw(); - The button will keep its own internal copies of these drawables. + /** Deletes a section of the text. - @param normalImage the thing to draw for the button's 'normal' state. An internal copy - will be made of the object passed-in if it is non-zero. - @param overImage the thing to draw for the button's 'over' state - if this is - zero, the button's normal image will be used when the mouse is - over it. An internal copy will be made of the object passed-in - if it is non-zero. - @param downImage the thing to draw for the button's 'down' state - if this is - zero, the 'over' image will be used instead (or the normal image - as a last resort). An internal copy will be made of the object - passed-in if it is non-zero. - @param disabledImage an image to draw when the button is disabled. If this is zero, - the normal image will be drawn with a reduced opacity instead. - An internal copy will be made of the object passed-in if it is - non-zero. - @param normalImageOn same as the normalImage, but this is used when the button's toggle - state is 'on'. If this is 0, the normal image is used instead - @param overImageOn same as the overImage, but this is used when the button's toggle - state is 'on'. If this is 0, the normalImageOn is drawn instead - @param downImageOn same as the downImage, but this is used when the button's toggle - state is 'on'. If this is 0, the overImageOn is drawn instead - @param disabledImageOn same as the disabledImage, but this is used when the button's toggle - state is 'on'. If this is 0, the normal image will be drawn instead - with a reduced opacity + This operation is undoable. */ - void setImages (const Drawable* normalImage, - const Drawable* overImage = 0, - const Drawable* downImage = 0, - const Drawable* disabledImage = 0, - const Drawable* normalImageOn = 0, - const Drawable* overImageOn = 0, - const Drawable* downImageOn = 0, - const Drawable* disabledImageOn = 0); + void deleteSection (const Position& startPosition, const Position& endPosition); - /** Changes the button's style. + /** Inserts some text into the document at a given position. - @see ButtonStyle + This operation is undoable. */ - void setButtonStyle (const ButtonStyle newStyle); + void insertText (const Position& position, const String& text); - /** Changes the button's background colours. + /** Clears the document and replaces it with some new text. - The toggledOffColour is the colour to use when the button's toggle state - is off, and toggledOnColour when it's on. + This operation is undoable - if you're trying to completely reset the document, you + might want to also call clearUndoHistory() and setSavePoint() after using this method. + */ + void replaceAllContent (const String& newContent); - For an ImageOnly or ImageAboveTextLabel style, the background colour is - used to fill the background of the component. + /** Returns the preferred new-line characters for the document. + This will be either "\n", "\r\n", or (rarely) "\r". + @see setNewLineCharacters + */ + const String getNewLineCharacters() const throw() { return newLineChars; } - For an ImageOnButtonBackground style, the colour is used to draw the - button's lozenge shape and exactly how the colour's used will depend - on the LookAndFeel. + /** Sets the new-line characters that the document should use. + The string must be either "\n", "\r\n", or (rarely) "\r". + @see getNewLineCharacters */ - void setBackgroundColours (const Colour& toggledOffColour, - const Colour& toggledOnColour); + void setNewLineCharacters (const String& newLine) throw(); - /** Returns the current background colour being used. + /** Begins a new undo transaction. - @see setBackgroundColour + The document itself will not call this internally, so relies on whatever is using the + document to periodically call this to break up the undo sequence into sensible chunks. + @see UndoManager::beginNewTransaction */ - const Colour& getBackgroundColour() const throw(); - - /** Gives the button an optional amount of space around the edge of the drawable. + void newTransaction(); - This will only apply to ImageFitted or ImageRaw styles, it won't affect the - ones on a button background. If the button is too small for the given gap, a - smaller gap will be used. + /** Undo the last operation. + @see UndoManager::undo + */ + void undo(); - By default there's a gap of about 3 pixels. + /** Redo the last operation. + @see UndoManager::redo */ - void setEdgeIndent (const int numPixelsIndent); + void redo(); - /** Returns the image that the button is currently displaying. */ - const Drawable* getCurrentImage() const throw(); - const Drawable* getNormalImage() const throw(); - const Drawable* getOverImage() const throw(); - const Drawable* getDownImage() const throw(); + /** Clears the undo history. + @see UndoManager::clearUndoHistory + */ + void clearUndoHistory(); - juce_UseDebuggingNewOperator + /** Returns the document's UndoManager */ + UndoManager& getUndoManager() throw() { return undoManager; } -protected: - /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); + /** Makes a note that the document's current state matches the one that is saved. -private: + After this has been called, hasChangedSinceSavePoint() will return false until + the document has been altered, and then it'll start returning true. If the document is + altered, but then undone until it gets back to this state, hasChangedSinceSavePoint() + will again return false. - ButtonStyle style; - Drawable* normalImage; - Drawable* overImage; - Drawable* downImage; - Drawable* disabledImage; - Drawable* normalImageOn; - Drawable* overImageOn; - Drawable* downImageOn; - Drawable* disabledImageOn; - Colour backgroundOff, backgroundOn; - int edgeIndent; + @see hasChangedSinceSavePoint + */ + void setSavePoint() throw(); - void deleteImages(); - DrawableButton (const DrawableButton&); - const DrawableButton& operator= (const DrawableButton&); -}; + /** Returns true if the state of the document differs from the state it was in when + setSavePoint() was last called. -#endif // __JUCE_DRAWABLEBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_DrawableButton.h *********/ + @see setSavePoint + */ + bool hasChangedSinceSavePoint() const throw(); -#endif -#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ + /** Searches for a word-break. */ + const Position findWordBreakAfter (const Position& position) const throw(); -/********* Start of inlined file: juce_HyperlinkButton.h *********/ -#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ -#define __JUCE_HYPERLINKBUTTON_JUCEHEADER__ + /** Searches for a word-break. */ + const Position findWordBreakBefore (const Position& position) const throw(); -/** - A button showing an underlined weblink, that will launch the link - when it's clicked. + /** An object that receives callbacks from the CodeDocument when its text changes. + @see CodeDocument::addListener, CodeDocument::removeListener + */ + class JUCE_API Listener + { + public: + Listener() {} + virtual ~Listener() {} - @see Button -*/ -class JUCE_API HyperlinkButton : public Button -{ -public: + /** Called by a CodeDocument when it is altered. + */ + virtual void codeDocumentChanged (const Position& affectedTextStart, + const Position& affectedTextEnd) = 0; + }; - /** Creates a HyperlinkButton. + /** Registers a listener object to receive callbacks when the document changes. + If the listener is already registered, this method has no effect. + @see removeListener + */ + void addListener (Listener* const listener) throw(); - @param linkText the text that will be displayed in the button - this is - also set as the Component's name, but the text can be - changed later with the Button::getButtonText() method - @param linkURL the URL to launch when the user clicks the button + /** Deregisters a listener. + @see addListener */ - HyperlinkButton (const String& linkText, - const URL& linkURL); + void removeListener (Listener* const listener) throw(); - /** Destructor. */ - ~HyperlinkButton(); + /** Iterates the text in a CodeDocument. - /** Changes the font to use for the text. + This class lets you read characters from a CodeDocument. It's designed to be used + by a SyntaxAnalyser object. - If resizeToMatchComponentHeight is true, the font's height will be adjusted - to match the size of the component. + @see CodeDocument, SyntaxAnalyser */ - void setFont (const Font& newFont, - const bool resizeToMatchComponentHeight, - const Justification& justificationType = Justification::horizontallyCentred); + class Iterator + { + public: + Iterator (CodeDocument* const document) throw(); + Iterator (const Iterator& other); + const Iterator& operator= (const Iterator& other) throw(); + ~Iterator() throw(); - /** A set of colour IDs to use to change the colour of various aspects of the link. + /** Reads the next character and returns it. + @see peekNextChar + */ + juce_wchar nextChar() throw(); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** Reads the next character without advancing the current position. */ + juce_wchar peekNextChar() const throw(); - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - textColourId = 0x1001f00, /**< The colour to use for the URL text. */ - }; + /** Advances the position by one character. */ + void skip() throw(); - /** Changes the URL that the button will trigger. */ - void setURL (const URL& newURL) throw(); + /** Returns the position of the next character as its position within the + whole document. + */ + int getPosition() const throw() { return position; } - /** Returns the URL that the button will trigger. */ - const URL& getURL() const throw() { return url; } + /** Skips over any whitespace characters until the next character is non-whitespace. */ + void skipWhitespace(); - /** Resizes the button horizontally to fit snugly around the text. + /** Skips forward until the next character will be the first character on the next line */ + void skipToEndOfLine(); - This won't affect the button's height. - */ - void changeWidthToFitText(); + /** Returns the line number of the next character. */ + int getLine() const throw() { return line; } - juce_UseDebuggingNewOperator + /** Returns true if the iterator has reached the end of the document. */ + bool isEOF() const throw(); -protected: - /** @internal */ - void clicked(); - /** @internal */ - void colourChanged(); - /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); + private: + CodeDocument* document; + int line, position; + }; + + juce_UseDebuggingNewOperator private: - URL url; - Font font; - bool resizeFont; - Justification justification; + friend class CodeDocumentInsertAction; + friend class CodeDocumentDeleteAction; + friend class Iterator; + friend class Position; - const Font getFontToUse() const; + OwnedArray lines; + Array positionsToMaintain; + UndoManager undoManager; + int currentActionIndex, indexOfSavedState; + int maximumLineLength; + VoidArray listeners; + String newLineChars; - HyperlinkButton (const HyperlinkButton&); - const HyperlinkButton& operator= (const HyperlinkButton&); + void sendListenerChangeMessage (const int startLine, const int endLine); + + void insert (const String& text, const int insertPos, const bool undoable); + void remove (const int startPos, const int endPos, const bool undoable); + + CodeDocument (const CodeDocument&); + const CodeDocument& operator= (const CodeDocument&); }; -#endif // __JUCE_HYPERLINKBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_HyperlinkButton.h *********/ +#endif // __JUCE_CODEDOCUMENT_JUCEHEADER__ +/********* End of inlined file: juce_CodeDocument.h *********/ #endif -#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ +#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ImageButton.h *********/ -#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ -#define __JUCE_IMAGEBUTTON_JUCEHEADER__ +/********* Start of inlined file: juce_CodeEditorComponent.h *********/ +#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ +#define __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ -/** - As the title suggests, this is a button containing an image. +/********* Start of inlined file: juce_CodeTokeniser.h *********/ +#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ +#define __JUCE_CODETOKENISER_JUCEHEADER__ - The colour and transparency of the image can be set to vary when the - button state changes. +/** + A base class for tokenising code so that the syntax can be displayed in a + code editor. - @see Button, ShapeButton, TextButton + @see CodeDocument, CodeEditorComponent */ -class JUCE_API ImageButton : public Button +class JUCE_API CodeTokeniser { public: + CodeTokeniser() {} + virtual ~CodeTokeniser() {} - /** Creates an ImageButton. - - Use setImage() to specify the image to use. The colours and opacities that - are specified here can be changed later using setDrawingOptions(). - - @param name the name to give the component - */ - ImageButton (const String& name); - - /** Destructor. */ - ~ImageButton(); - - /** Sets up the images to draw in various states. - - Important! Bear in mind that if you pass the same image in for more than one of - these parameters, this button will delete it (or release from the ImageCache) - multiple times! + /** Reads the next token from the source and returns its token type. - @param resizeButtonNowToFitThisImage if true, the button will be immediately - resized to the same dimensions as the normal image - @param rescaleImagesWhenButtonSizeChanges if true, the image will be rescaled to fit the - button when the button's size changes - @param preserveImageProportions if true then any rescaling of the image to fit - the button will keep the image's x and y proportions - correct - i.e. it won't distort its shape, although - this might create gaps around the edges - @param normalImage the image to use when the button is in its normal state. The - image passed in will be deleted (or released if it - was created by the ImageCache class) when the - button no longer needs it. - @param imageOpacityWhenNormal the opacity to use when drawing the normal image. - @param overlayColourWhenNormal an overlay colour to use to fill the alpha channel of the - normal image - if this colour is transparent, no overlay - will be drawn. The overlay will be drawn over the top of the - image, so you can basically add a solid or semi-transparent - colour to the image to brighten or darken it - @param overImage the image to use when the mouse is over the button. If - you want to use the same image as was set in the normalImage - parameter, this value can be 0. As for normalImage, it - will be deleted or released by the button when no longer - needed - @param imageOpacityWhenOver the opacity to use when drawing the image when the mouse - is over the button - @param overlayColourWhenOver an overlay colour to use to fill the alpha channel of the - image when the mouse is over - if this colour is transparent, - no overlay will be drawn - @param downImage an image to use when the button is pressed down. If set - to zero, the 'over' image will be drawn instead (or the - normal image if there isn't an 'over' image either). This - image will be deleted or released by the button when no - longer needed - @param imageOpacityWhenDown the opacity to use when drawing the image when the button - is pressed - @param overlayColourWhenDown an overlay colour to use to fill the alpha channel of the - image when the button is pressed down - if this colour is - transparent, no overlay will be drawn - @param hitTestAlphaThreshold if set to zero, the mouse is considered to be over the button - whenever it's inside the button's bounding rectangle. If - set to values higher than 0, the mouse will only be - considered to be over the image when the value of the - image's alpha channel at that position is greater than - this level. + This must leave the source pointing to the first character in the + next token. */ - void setImages (const bool resizeButtonNowToFitThisImage, - const bool rescaleImagesWhenButtonSizeChanges, - const bool preserveImageProportions, - Image* const normalImage, - const float imageOpacityWhenNormal, - const Colour& overlayColourWhenNormal, - Image* const overImage, - const float imageOpacityWhenOver, - const Colour& overlayColourWhenOver, - Image* const downImage, - const float imageOpacityWhenDown, - const Colour& overlayColourWhenDown, - const float hitTestAlphaThreshold = 0.0f); - - /** Returns the currently set 'normal' image. */ - Image* getNormalImage() const throw(); + virtual int readNextToken (CodeDocument::Iterator& source) = 0; - /** Returns the image that's drawn when the mouse is over the button. + /** Returns a list of the names of the token types this analyser uses. - If an 'over' image has been set, this will return it; otherwise it'll - just return the normal image. + The index in this list must match the token type numbers that are + returned by readNextToken(). */ - Image* getOverImage() const throw(); - - /** Returns the image that's drawn when the button is held down. + virtual const StringArray getTokenTypes() = 0; - If a 'down' image has been set, this will return it; otherwise it'll - return the 'over' image or normal image, depending on what's available. + /** Returns a suggested syntax highlighting colour for a specified + token type. */ - Image* getDownImage() const throw(); + virtual const Colour getDefaultColour (const int tokenType) = 0; juce_UseDebuggingNewOperator - -protected: - /** @internal */ - bool hitTest (int x, int y); - /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); - -private: - - bool scaleImageToFit, preserveProportions; - unsigned char alphaThreshold; - int imageX, imageY, imageW, imageH; - Image* normalImage; - Image* overImage; - Image* downImage; - float normalOpacity, overOpacity, downOpacity; - Colour normalOverlay, overOverlay, downOverlay; - - Image* getCurrentImage() const; - void deleteImages(); - - ImageButton (const ImageButton&); - const ImageButton& operator= (const ImageButton&); }; -#endif // __JUCE_IMAGEBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_ImageButton.h *********/ - -#endif -#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ +#endif // __JUCE_CODETOKENISER_JUCEHEADER__ +/********* End of inlined file: juce_CodeTokeniser.h *********/ -/********* Start of inlined file: juce_ShapeButton.h *********/ -#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ -#define __JUCE_SHAPEBUTTON_JUCEHEADER__ +class CodeEditorLine; /** - A button that contains a filled shape. + A text editor component designed specifically for source code. - @see Button, ImageButton, TextButton, ArrowButton + This is designed to handle syntax highlighting and fast editing of very large + files. */ -class JUCE_API ShapeButton : public Button +class JUCE_API CodeEditorComponent : public Component, + public Timer, + public ScrollBarListener, + public CodeDocument::Listener, + public AsyncUpdater { public: - /** Creates a ShapeButton. + /** Creates an editor for a document. - @param name a name to give the component - see Component::setName() - @param normalColour the colour to fill the shape with when the mouse isn't over - @param overColour the colour to use when the mouse is over the shape - @param downColour the colour to use when the button is in the pressed-down state + The tokeniser object is optional - pass 0 to disable syntax highlighting. + The object that you pass in is not owned or deleted by the editor - you must + make sure that it doesn't get deleted while this component is still using it. + + @see CodeDocument */ - ShapeButton (const String& name, - const Colour& normalColour, - const Colour& overColour, - const Colour& downColour); + CodeEditorComponent (CodeDocument& document, + CodeTokeniser* const codeTokeniser); /** Destructor. */ - ~ShapeButton(); + ~CodeEditorComponent(); - /** Sets the shape to use. + /** Returns the code document that this component is editing. */ + CodeDocument& getDocument() const throw() { return document; } - @param newShape the shape to use - @param resizeNowToFitThisShape if true, the button will be resized to fit the shape's bounds - @param maintainShapeProportions if true, the shape's proportions will be kept fixed when - the button is resized - @param hasDropShadow if true, the button will be given a drop-shadow effect + /** Loads the given content into the document. + This will completely reset the CodeDocument object, clear its undo history, + and fill it with this text. */ - void setShape (const Path& newShape, - const bool resizeNowToFitThisShape, - const bool maintainShapeProportions, - const bool hasDropShadow); + void loadContent (const String& newContent); - /** Set the colours to use for drawing the shape. + /** Returns the standard character width. */ + float getCharWidth() const throw() { return charWidth; } - @param normalColour the colour to fill the shape with when the mouse isn't over - @param overColour the colour to use when the mouse is over the shape - @param downColour the colour to use when the button is in the pressed-down state + /** Returns the height of a line of text, in pixels. */ + int getLineHeight() const throw() { return lineHeight; } + + /** Returns the number of whole lines visible on the screen, + This doesn't include a cut-off line that might be visible at the bottom if the + component's height isn't an exact multiple of the line-height. */ - void setColours (const Colour& normalColour, - const Colour& overColour, - const Colour& downColour); + int getNumLinesOnScreen() const throw() { return linesOnScreen; } - /** Sets up an outline to draw around the shape. + /** Returns the number of whole columns visible on the screen. + This doesn't include any cut-off columns at the right-hand edge. + */ + int getNumColumnsOnScreen() const throw() { return columnsOnScreen; } - @param outlineColour the colour to use - @param outlineStrokeWidth the thickness of line to draw + /** Returns the current caret position. */ + const CodeDocument::Position getCaretPos() const { return caretPos; } + + /** Moves the caret. + If selecting is true, the section of the document between the current + caret position and the new one will become selected. If false, any currently + selected region will be deselected. */ - void setOutline (const Colour& outlineColour, - const float outlineStrokeWidth); + void moveCaretTo (const CodeDocument::Position& newPos, const bool selecting); - juce_UseDebuggingNewOperator + /** Returns the on-screen position of a character in the document. + The rectangle returned is relative to this component's top-left origin. + */ + const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw(); -protected: - /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); + /** Finds the character at a given on-screen position. + The co-ordinates are relative to this component's top-left origin. + */ + const CodeDocument::Position getPositionAt (int x, int y); -private: - Colour normalColour, overColour, downColour, outlineColour; - DropShadowEffect shadow; - Path shape; - bool maintainShapeProportions; - float outlineWidth; + void cursorLeft (const bool moveInWholeWordSteps, const bool selecting); + void cursorRight (const bool moveInWholeWordSteps, const bool selecting); + void cursorDown (const bool selecting); + void cursorUp (const bool selecting); - ShapeButton (const ShapeButton&); - const ShapeButton& operator= (const ShapeButton&); -}; + void pageDown (const bool selecting); + void pageUp (const bool selecting); -#endif // __JUCE_SHAPEBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_ShapeButton.h *********/ + void scrollDown(); + void scrollUp(); + void scrollToLine (int newFirstLineOnScreen); + void scrollBy (int deltaLines); + void scrollToColumn (int newFirstColumnOnScreen); + void scrollToKeepCaretOnScreen(); -#endif -#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ + void goToStartOfDocument (const bool selecting); + void goToStartOfLine (const bool selecting); + void goToEndOfDocument (const bool selecting); + void goToEndOfLine (const bool selecting); -#endif -#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ + void deselectAll(); + void selectAll(); -/********* Start of inlined file: juce_ToggleButton.h *********/ -#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ -#define __JUCE_TOGGLEBUTTON_JUCEHEADER__ + void insertTextAtCaret (const String& textToInsert); + void insertTabAtCaret(); + void cut(); + void copy(); + void copyThenCut(); + void paste(); + void backspace (const bool moveInWholeWordSteps); + void deleteForward (const bool moveInWholeWordSteps); -/** - A button that can be toggled on/off. + void undo(); + void redo(); - All buttons can be toggle buttons, but this lets you create one of the - standard ones which has a tick-box and a text label next to it. + /** Changes the current tab settings. + This lets you change the tab size and whether pressing the tab key inserts a + tab character, or its equivalent number of spaces. + */ + void setTabSize (const int numSpacesPerTab, + const bool insertSpacesInsteadOfTabCharacters) throw(); - @see Button, DrawableButton, TextButton -*/ -class JUCE_API ToggleButton : public Button -{ -public: + /** Returns the current number of spaces per tab. + @see setTabSize + */ + int getTabSize() const throw() { return spacesPerTab; } - /** Creates a ToggleButton. + /** Returns true if the tab key will insert spaces instead of actual tab characters. + @see setTabSize + */ + bool areSpacesInsertedForTabs() const { return useSpacesForTabs; } - @param buttonText the text to put in the button (the component's name is also - initially set to this string, but these can be changed later - using the setName() and setButtonText() methods) + /** Changes the font. + Make sure you only use a fixed-width font, or this component will look pretty nasty! */ - ToggleButton (const String& buttonText); + void setFont (const Font& newFont); - /** Destructor. */ - ~ToggleButton(); + /** Resets the syntax highlighting colours to the default ones provided by the + code tokeniser. + @see CodeTokeniser::getDefaultColour + */ + void resetToDefaultColours(); - /** Resizes the button to fit neatly around its current text. + /** Changes one of the syntax highlighting colours. + The token type values are dependent on the tokeniser being used - use + CodeTokeniser::getTokenTypes() to get a list of the token types. + @see getColourForTokenType + */ + void setColourForTokenType (const int tokenType, const Colour& colour); - The button's height won't be affected, only its width. + /** Returns one of the syntax highlighting colours. + The token type values are dependent on the tokeniser being used - use + CodeTokeniser::getTokenTypes() to get a list of the token types. + @see setColourForTokenType */ - void changeWidthToFitText(); + const Colour getColourForTokenType (const int tokenType) const throw(); - /** A set of colour IDs to use to change the colour of various aspects of the button. + /** A set of colour IDs to use to change the colour of various aspects of the editor. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @@ -42678,2779 +42112,2603 @@ public: */ enum ColourIds { - textColourId = 0x1006501 /**< The colour to use for the button's text. */ + backgroundColourId = 0x1004500, /**< A colour to use to fill the editor's background. */ + caretColourId = 0x1004501, /**< The colour to draw the caret. */ + highlightColourId = 0x1004502, /**< The colour to use for the highlighted background under + selected text. */ + defaultTextColourId = 0x1004503 /**< The colour to use for text when no syntax colouring is + enabled. */ }; - juce_UseDebuggingNewOperator + /** Changes the size of the scrollbars. */ + void setScrollbarThickness (const int thickness) throw(); -protected: /** @internal */ - void paintButton (Graphics& g, - bool isMouseOverButton, - bool isButtonDown); - + void resized(); /** @internal */ - void colourChanged(); + void paint (Graphics& g); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void mouseDoubleClick (const MouseEvent& e); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + void timerCallback(); + /** @internal */ + void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart); + /** @internal */ + void handleAsyncUpdate(); + /** @internal */ + void codeDocumentChanged (const CodeDocument::Position& affectedTextStart, + const CodeDocument::Position& affectedTextEnd); + + juce_UseDebuggingNewOperator private: + CodeDocument& document; - ToggleButton (const ToggleButton&); - const ToggleButton& operator= (const ToggleButton&); -}; + Font font; + int firstLineOnScreen, gutter, spacesPerTab; + float charWidth; + int lineHeight, linesOnScreen, columnsOnScreen; + int scrollbarThickness; + bool useSpacesForTabs; + double xOffset; -#endif // __JUCE_TOGGLEBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_ToggleButton.h *********/ + CodeDocument::Position caretPos; + CodeDocument::Position selectionStart, selectionEnd; + Component* caret; + ScrollBar* verticalScrollBar; + ScrollBar* horizontalScrollBar; -#endif -#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ + enum DragType + { + notDragging, + draggingSelectionStart, + draggingSelectionEnd + }; -/********* Start of inlined file: juce_ToolbarButton.h *********/ -#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ -#define __JUCE_TOOLBARBUTTON_JUCEHEADER__ - -/********* Start of inlined file: juce_ToolbarItemComponent.h *********/ -#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ -#define __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ - -/********* Start of inlined file: juce_Toolbar.h *********/ -#ifndef __JUCE_TOOLBAR_JUCEHEADER__ -#define __JUCE_TOOLBAR_JUCEHEADER__ - -/********* Start of inlined file: juce_DragAndDropContainer.h *********/ -#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ -#define __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ - -/********* Start of inlined file: juce_DragAndDropTarget.h *********/ -#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ -#define __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ - -/** - Components derived from this class can have things dropped onto them by a DragAndDropContainer. - - To create a component that can receive things drag-and-dropped by a DragAndDropContainer, - derive your component from this class, and make sure that it is somewhere inside a - DragAndDropContainer component. + DragType dragType; - Note: If all that you need to do is to respond to files being drag-and-dropped from - the operating system onto your component, you don't need any of these classes: instead - see the FileDragAndDropTarget class. + CodeTokeniser* codeTokeniser; + Array coloursForTokenCategories; - @see DragAndDropContainer, FileDragAndDropTarget -*/ -class JUCE_API DragAndDropTarget -{ -public: - /** Destructor. */ - virtual ~DragAndDropTarget() {} + OwnedArray lines; + void rebuildLineTokens(); - /** Callback to check whether this target is interested in the type of object being - dragged. + OwnedArray cachedIterators; + void clearCachedIterators (const int firstLineToBeInvalid) throw(); + void updateCachedIterators (int maxLineNum); + void getIteratorForPosition (int position, CodeDocument::Iterator& result); - @param sourceDescription the description string passed into DragAndDropContainer::startDragging() - @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() - @returns true if this component wants to receive the other callbacks regarging this - type of object; if it returns false, no other callbacks will be made. - */ - virtual bool isInterestedInDragSource (const String& sourceDescription, - Component* sourceComponent) = 0; + void updateScrollBars(); + void scrollToLineInternal (int line); + void scrollToColumnInternal (double column); + void newTransaction(); - /** Callback to indicate that something is being dragged over this component. + int indexToColumn (int line, int index) const throw(); + int columnToIndex (int line, int column) const throw(); - This gets called when the user moves the mouse into this component while dragging - something. + CodeEditorComponent (const CodeEditorComponent&); + const CodeEditorComponent& operator= (const CodeEditorComponent&); +}; - Use this callback as a trigger to make your component repaint itself to give the - user feedback about whether the item can be dropped here or not. +#endif // __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_CodeEditorComponent.h *********/ - @param sourceDescription the description string passed into DragAndDropContainer::startDragging() - @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component - @see itemDragExit - */ - virtual void itemDragEnter (const String& sourceDescription, - Component* sourceComponent, - int x, - int y); +#endif +#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ - /** Callback to indicate that the user is dragging something over this component. +#endif +#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ - This gets called when the user moves the mouse over this component while dragging - something. Normally overriding itemDragEnter() and itemDragExit() are enough, but - this lets you know what happens in-between. +/********* Start of inlined file: juce_CPlusPlusCodeTokeniser.h *********/ +#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ +#define __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ - @param sourceDescription the description string passed into DragAndDropContainer::startDragging() - @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component - */ - virtual void itemDragMove (const String& sourceDescription, - Component* sourceComponent, - int x, - int y); +/** + A simple lexical analyser for syntax colouring of C++ code. - /** Callback to indicate that something has been dragged off the edge of this component. + @see SyntaxAnalyser, CodeEditorComponent, CodeDocument +*/ +class JUCE_API CPlusPlusCodeTokeniser : public CodeTokeniser +{ +public: - This gets called when the user moves the mouse out of this component while dragging - something. + CPlusPlusCodeTokeniser(); + ~CPlusPlusCodeTokeniser(); - If you've used itemDragEnter() to repaint your component and give feedback, use this - as a signal to repaint it in its normal state. + enum TokenType + { + tokenType_error = 0, + tokenType_comment, + tokenType_builtInKeyword, + tokenType_identifier, + tokenType_integerLiteral, + tokenType_floatLiteral, + tokenType_stringLiteral, + tokenType_operator, + tokenType_bracket, + tokenType_punctuation, + tokenType_preprocessor + }; - @param sourceDescription the description string passed into DragAndDropContainer::startDragging() - @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() - @see itemDragEnter - */ - virtual void itemDragExit (const String& sourceDescription, - Component* sourceComponent); + int readNextToken (CodeDocument::Iterator& source); + const StringArray getTokenTypes(); + const Colour getDefaultColour (const int tokenType); - /** Callback to indicate that the user has dropped something onto this component. + juce_UseDebuggingNewOperator +}; - When the user drops an item this get called, and you can use the description to - work out whether your object wants to deal with it or not. +#endif // __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ +/********* End of inlined file: juce_CPlusPlusCodeTokeniser.h *********/ - Note that after this is called, the itemDragExit method may not be called, so you should - clean up in here if there's anything you need to do when the drag finishes. +#endif +#ifndef __JUCE_COMBOBOX_JUCEHEADER__ - @param sourceDescription the description string passed into DragAndDropContainer::startDragging() - @param sourceComponent the component that was passed into DragAndDropContainer::startDragging() - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component - */ - virtual void itemDropped (const String& sourceDescription, - Component* sourceComponent, - int x, - int y) = 0; +#endif +#ifndef __JUCE_LABEL_JUCEHEADER__ - /** Overriding this allows the target to tell the drag container whether to - draw the drag image while the cursor is over it. +#endif +#ifndef __JUCE_LISTBOX_JUCEHEADER__ - By default it returns true, but if you return false, then the normal drag - image will not be shown when the cursor is over this target. - */ - virtual bool shouldDrawDragImageWhenOver(); -}; +#endif +#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ -#endif // __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ -/********* End of inlined file: juce_DragAndDropTarget.h *********/ +/********* Start of inlined file: juce_ProgressBar.h *********/ +#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ +#define __JUCE_PROGRESSBAR_JUCEHEADER__ /** - Enables drag-and-drop behaviour for a component and all its sub-components. - - For a component to be able to make or receive drag-and-drop events, one of its parent - components must derive from this class. It's probably best for the top-level - component to implement it. + A progress bar component. - Then to start a drag operation, any sub-component can just call the startDragging() - method, and this object will take over, tracking the mouse and sending appropriate - callbacks to any child components derived from DragAndDropTarget which the mouse - moves over. + To use this, just create one and make it visible. It'll run its own timer + to keep an eye on a variable that you give it, and will automatically + redraw itself when the variable changes. - Note: If all that you need to do is to respond to files being drag-and-dropped from - the operating system onto your component, you don't need any of these classes: you can do this - simply by overriding Component::filesDropped(). + For an easy way of running a background task with a dialog box showing its + progress, see the ThreadWithProgressWindow class. - @see DragAndDropTarget + @see ThreadWithProgressWindow */ -class JUCE_API DragAndDropContainer +class JUCE_API ProgressBar : public Component, + public SettableTooltipClient, + private Timer { public: - /** Creates a DragAndDropContainer. + /** Creates a ProgressBar. - The object that derives from this class must also be a Component. + @param progress pass in a reference to a double that you're going to + update with your task's progress. The ProgressBar will + monitor the value of this variable and will redraw itself + when the value changes. The range is from 0 to 1.0. Obviously + you'd better be careful not to delete this variable while the + ProgressBar still exists! */ - DragAndDropContainer(); + ProgressBar (double& progress); /** Destructor. */ - virtual ~DragAndDropContainer(); - - /** Begins a drag-and-drop operation. - - This starts a drag-and-drop operation - call it when the user drags the - mouse in your drag-source component, and this object will track mouse - movements until the user lets go of the mouse button, and will send - appropriate messages to DragAndDropTarget objects that the mouse moves - over. - - findParentDragContainerFor() is a handy method to call to find the - drag container to use for a component. - - @param sourceDescription a string to use as the description of the thing being - dragged - this will be passed to the objects that might be - dropped-onto so they can decide if they want to handle it or - not - @param sourceComponent the component that is being dragged - @param dragImage the image to drag around underneath the mouse. If this is - zero, a snapshot of the sourceComponent will be used instead. An - image passed-in will be deleted by this object when no longer - needed. - @param allowDraggingToOtherJuceWindows if true, the dragged component will appear as a desktop - window, and can be dragged to DragAndDropTargets that are the - children of components other than this one. - @param imageOffsetFromMouse if an image has been passed-in, this specifies the offset - at which the image should be drawn from the mouse. If it isn't - specified, then the image will be centred around the mouse. If - an image hasn't been passed-in, this will be ignored. - */ - void startDragging (const String& sourceDescription, - Component* sourceComponent, - Image* dragImage = 0, - const bool allowDraggingToOtherJuceWindows = false, - const Point* imageOffsetFromMouse = 0); - - /** Returns true if something is currently being dragged. */ - bool isDragAndDropActive() const; - - /** Returns the description of the thing that's currently being dragged. - - If nothing's being dragged, this will return an empty string, otherwise it's the - string that was passed into startDragging(). - - @see startDragging - */ - const String getCurrentDragDescription() const; - - /** Utility to find the DragAndDropContainer for a given Component. - - This will search up this component's parent hierarchy looking for the first - parent component which is a DragAndDropContainer. + ~ProgressBar(); - It's useful when a component wants to call startDragging but doesn't know - the DragAndDropContainer it should to use. + /** Turns the percentage display on or off. - Obviously this may return 0 if it doesn't find a suitable component. + By default this is on, and the progress bar will display a text string showing + its current percentage. */ - static DragAndDropContainer* findParentDragContainerFor (Component* childComponent); - - /** This performs a synchronous drag-and-drop of a set of files to some external - application. + void setPercentageDisplay (const bool shouldDisplayPercentage); - You can call this function in response to a mouseDrag callback, and it will - block, running its own internal message loop and tracking the mouse, while it - uses a native operating system drag-and-drop operation to move or copy some - files to another application. + /** Gives the progress bar a string to display inside it. - @param files a list of filenames to drag - @param canMoveFiles if true, the app that receives the files is allowed to move the files to a new location - (if this is appropriate). If false, the receiver is expected to make a copy of them. - @returns true if the files were successfully dropped somewhere, or false if it - was interrupted - @see performExternalDragDropOfText + If you call this, it will turn off the percentage display. + @see setPercentageDisplay */ - static bool performExternalDragDropOfFiles (const StringArray& files, const bool canMoveFiles); + void setTextToDisplay (const String& text); - /** This performs a synchronous drag-and-drop of a block of text to some external - application. + /** A set of colour IDs to use to change the colour of various aspects of the bar. - You can call this function in response to a mouseDrag callback, and it will - block, running its own internal message loop and tracking the mouse, while it - uses a native operating system drag-and-drop operation to move or copy some - text to another application. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - @param text the text to copy - @returns true if the text was successfully dropped somewhere, or false if it - was interrupted - @see performExternalDragDropOfFiles + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - static bool performExternalDragDropOfText (const String& text); + enum ColourIds + { + backgroundColourId = 0x1001900, /**< The background colour, behind the bar. */ + foregroundColourId = 0x1001a00, /**< The colour to use to draw the bar itself. LookAndFeel + classes will probably use variations on this colour. */ + }; juce_UseDebuggingNewOperator protected: - /** Override this if you want to be able to perform an external drag a set of files - when the user drags outside of this container component. + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + void visibilityChanged(); + /** @internal */ + void colourChanged(); - This method will be called when a drag operation moves outside the Juce-based window, - and if you want it to then perform a file drag-and-drop, add the filenames you want - to the array passed in, and return true. +private: + double& progress; + double currentValue; + bool displayPercentage; + String displayedMessage, currentMessage; + uint32 lastCallbackTime; - @param dragSourceDescription the description passed into the startDrag() call when the drag began - @param dragSourceComponent the component passed into the startDrag() call when the drag began - @param files on return, the filenames you want to drag - @param canMoveFiles on return, true if it's ok for the receiver to move the files; false if - it must make a copy of them (see the performExternalDragDropOfFiles() - method) - @see performExternalDragDropOfFiles - */ - virtual bool shouldDropFilesWhenDraggedExternally (const String& dragSourceDescription, - Component* dragSourceComponent, - StringArray& files, - bool& canMoveFiles); + void timerCallback(); -private: - friend class DragImageComponent; - Component* dragImageComponent; - String currentDragDesc; + ProgressBar (const ProgressBar&); + const ProgressBar& operator= (const ProgressBar&); }; -#endif // __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ -/********* End of inlined file: juce_DragAndDropContainer.h *********/ +#endif // __JUCE_PROGRESSBAR_JUCEHEADER__ +/********* End of inlined file: juce_ProgressBar.h *********/ -/********* Start of inlined file: juce_ComponentAnimator.h *********/ -#ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ -#define __JUCE_COMPONENTANIMATOR_JUCEHEADER__ +#endif +#ifndef __JUCE_SLIDER_JUCEHEADER__ -/** - Animates a set of components, moving it to a new position. +/********* Start of inlined file: juce_Slider.h *********/ +#ifndef __JUCE_SLIDER_JUCEHEADER__ +#define __JUCE_SLIDER_JUCEHEADER__ - To use this, create a ComponentAnimator, and use its animateComponent() method - to tell it to move components to destination positions. Any number of - components can be animated by one ComponentAnimator object (if you've got a - lot of components to move, it's much more efficient to share a single animator - than to have many animators running at once). +/********* Start of inlined file: juce_SliderListener.h *********/ +#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ +#define __JUCE_SLIDERLISTENER_JUCEHEADER__ - You'll need to make sure the animator object isn't deleted before it finishes - moving the components. +class Slider; - The class is a ChangeBroadcaster and sends a notification when any components - start or finish being animated. +/** + A class for receiving callbacks from a Slider. + + To be told when a slider's value changes, you can register a SliderListener + object using Slider::addListener(). + + @see Slider::addListener, Slider::removeListener */ -class JUCE_API ComponentAnimator : public ChangeBroadcaster, - private Timer +class JUCE_API SliderListener { public: - /** Creates a ComponentAnimator. */ - ComponentAnimator(); - /** Destructor. */ - ~ComponentAnimator(); + virtual ~SliderListener() {} - /** Starts a component moving from its current position to a specified position. + /** Called when the slider's value is changed. - If the component is already in the middle of an animation, that will be abandoned, - and a new animation will begin, moving the component from its current location. + This may be caused by dragging it, or by typing in its text entry box, + or by a call to Slider::setValue(). - The start and end speed parameters let you apply some acceleration to the component's - movement. + You can find out the new value using Slider::getValue(). - @param component the component to move - @param finalPosition the destination position and size to move it to - @param millisecondsToSpendMoving how long, in milliseconds, it should take - to arrive at its destination - @param startSpeed a value to indicate the relative start speed of the - animation. If this is 0, the component will start - by accelerating from rest; higher values mean that it - will have an initial speed greater than zero. If the - value if greater than 1, it will decelerate towards the - middle of its journey. To move the component at a constant - rate for its entire animation, set both the start and - end speeds to 1.0 - @param endSpeed a relative speed at which the component should be moving - when the animation finishes. If this is 0, the component - will decelerate to a standstill at its final position; higher - values mean the component will still be moving when it stops. - To move the component at a constant rate for its entire - animation, set both the start and end speeds to 1.0 + @see Slider::valueChanged */ - void animateComponent (Component* const component, - const Rectangle& finalPosition, - const int millisecondsToSpendMoving, - const double startSpeed = 1.0, - const double endSpeed = 1.0); - - /** Stops a component if it's currently being animated. + virtual void sliderValueChanged (Slider* slider) = 0; - If moveComponentToItsFinalPosition is true, then the component will - be immediately moved to its destination position and size. If false, it will be - left in whatever location it currently occupies. - */ - void cancelAnimation (Component* const component, - const bool moveComponentToItsFinalPosition); + /** Called when the slider is about to be dragged. - /** Clears all of the active animations. + This is called when a drag begins, then it's followed by multiple calls + to sliderValueChanged(), and then sliderDragEnded() is called after the + user lets go. - If moveComponentsToTheirFinalPositions is true, all the components will - be immediately set to their final positions. If false, they will be - left in whatever locations they currently occupy. + @see sliderDragEnded, Slider::startedDragging */ - void cancelAllAnimations (const bool moveComponentsToTheirFinalPositions); - - /** Returns the destination position for a component. - - If the component is being animated, this will return the target position that - was specified when animateComponent() was called. + virtual void sliderDragStarted (Slider* slider); - If the specified component isn't currently being animated, this method will just - return its current position. - */ - const Rectangle getComponentDestination (Component* const component); + /** Called after a drag operation has finished. - /** Returns true if the specified component is currently being animated. + @see sliderDragStarted, Slider::stoppedDragging */ - bool isAnimating (Component* component) const; - - juce_UseDebuggingNewOperator - -private: - VoidArray tasks; - uint32 lastTime; - - void* findTaskFor (Component* const component) const; - void timerCallback(); + virtual void sliderDragEnded (Slider* slider); }; -#endif // __JUCE_COMPONENTANIMATOR_JUCEHEADER__ -/********* End of inlined file: juce_ComponentAnimator.h *********/ - -class ToolbarItemComponent; -class ToolbarItemFactory; -class MissingItemsComponent; +#endif // __JUCE_SLIDERLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_SliderListener.h *********/ /** - A toolbar component. + A slider control for changing a value. - A toolbar contains a horizontal or vertical strip of ToolbarItemComponents, - and looks after their order and layout. + The slider can be horizontal, vertical, or rotary, and can optionally have + a text-box inside it to show an editable display of the current value. - Items (icon buttons or other custom components) are added to a toolbar using a - ToolbarItemFactory - each type of item is given a unique ID number, and a - toolbar might contain more than one instance of a particular item type. + To use it, create a Slider object and use the setSliderStyle() method + to set up the type you want. To set up the text-entry box, use setTextBoxStyle(). - Toolbars can be interactively customised, allowing the user to drag the items - around, and to drag items onto or off the toolbar, using the ToolbarItemPalette - component as a source of new items. + To define the values that it can be set to, see the setRange() and setValue() methods. - @see ToolbarItemFactory, ToolbarItemComponent, ToolbarItemPalette + There are also lots of custom tweaks you can do by subclassing and overriding + some of the virtual methods, such as changing the scaling, changing the format of + the text display, custom ways of limiting the values, etc. + + You can register SliderListeners with a slider, which will be informed when the value + changes, or a subclass can override valueChanged() to be informed synchronously. + + @see SliderListener */ -class JUCE_API Toolbar : public Component, - public DragAndDropContainer, - public DragAndDropTarget, - private ButtonListener +class JUCE_API Slider : public Component, + public SettableTooltipClient, + private AsyncUpdater, + private ButtonListener, + private LabelListener { public: - /** Creates an empty toolbar component. + /** Creates a slider. - To add some icons or other components to your toolbar, you'll need to - create a ToolbarItemFactory class that can create a suitable set of - ToolbarItemComponents. - - @see ToolbarItemFactory, ToolbarItemComponents + When created, you'll need to set up the slider's style and range with setSliderStyle(), + setRange(), etc. */ - Toolbar(); + Slider (const String& componentName); - /** Destructor. + /** Destructor. */ + ~Slider(); - Any items on the bar will be deleted when the toolbar is deleted. + /** The types of slider available. + + @see setSliderStyle, setRotaryParameters */ - ~Toolbar(); + enum SliderStyle + { + LinearHorizontal, /**< A traditional horizontal slider. */ + LinearVertical, /**< A traditional vertical slider. */ + LinearBar, /**< A horizontal bar slider with the text label drawn on top of it. */ + Rotary, /**< A rotary control that you move by dragging the mouse in a circular motion, like a knob. + @see setRotaryParameters */ + RotaryHorizontalDrag, /**< A rotary control that you move by dragging the mouse left-to-right. + @see setRotaryParameters */ + RotaryVerticalDrag, /**< A rotary control that you move by dragging the mouse up-and-down. + @see setRotaryParameters */ + IncDecButtons, /**< A pair of buttons that increment or decrement the slider's value by the increment set in setRange(). */ - /** Changes the bar's orientation. - @see isVertical + TwoValueHorizontal, /**< A horizontal slider that has two thumbs instead of one, so it can show a minimum and maximum value. + @see setMinValue, setMaxValue */ + TwoValueVertical, /**< A vertical slider that has two thumbs instead of one, so it can show a minimum and maximum value. + @see setMinValue, setMaxValue */ + + ThreeValueHorizontal, /**< A horizontal slider that has three thumbs instead of one, so it can show a minimum and maximum + value, with the current value being somewhere between them. + @see setMinValue, setMaxValue */ + ThreeValueVertical, /**< A vertical slider that has three thumbs instead of one, so it can show a minimum and maximum + value, with the current value being somewhere between them. + @see setMinValue, setMaxValue */ + }; + + /** Changes the type of slider interface being used. + + @param newStyle the type of interface + @see setRotaryParameters, setVelocityBasedMode, */ - void setVertical (const bool shouldBeVertical); + void setSliderStyle (const SliderStyle newStyle); - /** Returns true if the bar is set to be vertical, or false if it's horizontal. + /** Returns the slider's current style. - You can change the bar's orientation with setVertical(). + @see setSliderStyle */ - bool isVertical() const throw() { return vertical; } + SliderStyle getSliderStyle() const throw() { return style; } - /** Returns the depth of the bar. + /** Changes the properties of a rotary slider. - If the bar is horizontal, this will return its height; if it's vertical, it - will return its width. + @param startAngleRadians the angle (in radians, clockwise from the top) at which + the slider's minimum value is represented + @param endAngleRadians the angle (in radians, clockwise from the top) at which + the slider's maximum value is represented. This must be + greater than startAngleRadians + @param stopAtEnd if true, then when the slider is dragged around past the + minimum or maximum, it'll stop there; if false, it'll wrap + back to the opposite value + */ + void setRotaryParameters (const float startAngleRadians, + const float endAngleRadians, + const bool stopAtEnd); - @see getLength + /** Sets the distance the mouse has to move to drag the slider across + the full extent of its range. + + This only applies when in modes like RotaryHorizontalDrag, where it's using + relative mouse movements to adjust the slider. */ - int getThickness() const throw(); + void setMouseDragSensitivity (const int distanceForFullScaleDrag); - /** Returns the length of the bar. + /** Changes the way the the mouse is used when dragging the slider. - If the bar is horizontal, this will return its width; if it's vertical, it - will return its height. + If true, this will turn on velocity-sensitive dragging, so that + the faster the mouse moves, the bigger the movement to the slider. This + helps when making accurate adjustments if the slider's range is quite large. - @see getThickness + If false, the slider will just try to snap to wherever the mouse is. */ - int getLength() const throw(); + void setVelocityBasedMode (const bool isVelocityBased) throw(); - /** Deletes all items from the bar. + /** Returns true if velocity-based mode is active. + @see setVelocityBasedMode */ - void clear(); - - /** Adds an item to the toolbar. + bool getVelocityBasedMode() const throw() { return isVelocityBased; } - The factory's ToolbarItemFactory::createItem() will be called by this method - to create the component that will actually be added to the bar. + /** Changes aspects of the scaling used when in velocity-sensitive mode. - The new item will be inserted at the specified index (if the index is -1, it - will be added to the right-hand or bottom end of the bar). + These apply when you've used setVelocityBasedMode() to turn on velocity mode, + or if you're holding down ctrl. - Once added, the component will be automatically deleted by this object when it - is no longer needed. + @param sensitivity higher values than 1.0 increase the range of acceleration used + @param threshold the minimum number of pixels that the mouse needs to move for it + to be treated as a movement + @param offset values greater than 0.0 increase the minimum speed that will be used when + the threshold is reached + @param userCanPressKeyToSwapMode if true, then the user can hold down the ctrl or command + key to toggle velocity-sensitive mode + */ + void setVelocityModeParameters (const double sensitivity = 1.0, + const int threshold = 1, + const double offset = 0.0, + const bool userCanPressKeyToSwapMode = true) throw(); - @see ToolbarItemFactory + /** Returns the velocity sensitivity setting. + @see setVelocityModeParameters */ - void addItem (ToolbarItemFactory& factory, - const int itemId, - const int insertIndex = -1); + double getVelocitySensitivity() const throw() { return velocityModeSensitivity; } - /** Deletes one of the items from the bar. + /** Returns the velocity threshold setting. + @see setVelocityModeParameters */ - void removeToolbarItem (const int itemIndex); + int getVelocityThreshold() const throw() { return velocityModeThreshold; } - /** Returns the number of items currently on the toolbar. + /** Returns the velocity offset setting. + @see setVelocityModeParameters + */ + double getVelocityOffset() const throw() { return velocityModeOffset; } - @see getItemId, getItemComponent + /** Returns the velocity user key setting. + @see setVelocityModeParameters */ - int getNumItems() const throw(); + bool getVelocityModeIsSwappable() const throw() { return userKeyOverridesVelocity; } - /** Returns the ID of the item with the given index. + /** Sets up a skew factor to alter the way values are distributed. - If the index is less than zero or greater than the number of items, - this will return 0. + You may want to use a range of values on the slider where more accuracy + is required towards one end of the range, so this will logarithmically + spread the values across the length of the slider. - @see getNumItems + If the factor is < 1.0, the lower end of the range will fill more of the + slider's length; if the factor is > 1.0, the upper end of the range + will be expanded instead. A factor of 1.0 doesn't skew it at all. + + To set the skew position by using a mid-point, use the setSkewFactorFromMidPoint() + method instead. + + @see getSkewFactor, setSkewFactorFromMidPoint */ - int getItemId (const int itemIndex) const throw(); + void setSkewFactor (const double factor) throw(); - /** Returns the component being used for the item with the given index. + /** Sets up a skew factor to alter the way values are distributed. - If the index is less than zero or greater than the number of items, - this will return 0. + This allows you to specify the slider value that should appear in the + centre of the slider's visible range. - @see getNumItems - */ - ToolbarItemComponent* getItemComponent (const int itemIndex) const throw(); + @see setSkewFactor, getSkewFactor + */ + void setSkewFactorFromMidPoint (const double sliderValueToShowAtMidPoint) throw(); - /** Clears this toolbar and adds to it the default set of items that the specified - factory creates. + /** Returns the current skew factor. - @see ToolbarItemFactory::getDefaultItemSet + See setSkewFactor for more info. + + @see setSkewFactor, setSkewFactorFromMidPoint */ - void addDefaultItems (ToolbarItemFactory& factoryToUse); + double getSkewFactor() const throw() { return skewFactor; } - /** Options for the way items should be displayed. - @see setStyle, getStyle + /** Used by setIncDecButtonsMode(). */ - enum ToolbarItemStyle + enum IncDecButtonMode { - iconsOnly, /**< Means that the toolbar should just contain icons. */ - iconsWithText, /**< Means that the toolbar should have text labels under each icon. */ - textOnly /**< Means that the toolbar only display text labels for each item. */ + incDecButtonsNotDraggable, + incDecButtonsDraggable_AutoDirection, + incDecButtonsDraggable_Horizontal, + incDecButtonsDraggable_Vertical }; - /** Returns the toolbar's current style. - @see ToolbarItemStyle, setStyle - */ - ToolbarItemStyle getStyle() const throw() { return toolbarStyle; } + /** When the style is IncDecButtons, this lets you turn on a mode where the mouse + can be dragged on the buttons to drag the values. - /** Changes the toolbar's current style. - @see ToolbarItemStyle, getStyle, ToolbarItemComponent::setStyle + By default this is turned off. When enabled, clicking on the buttons still works + them as normal, but by holding down the mouse on a button and dragging it a little + distance, it flips into a mode where the value can be dragged. The drag direction can + either be set explicitly to be vertical or horizontal, or can be set to + incDecButtonsDraggable_AutoDirection so that it depends on whether the buttons + are side-by-side or above each other. */ - void setStyle (const ToolbarItemStyle& newStyle); + void setIncDecButtonsMode (const IncDecButtonMode mode); - /** Flags used by the showCustomisationDialog() method. */ - enum CustomisationFlags - { - allowIconsOnlyChoice = 1, /**< If this flag is specified, the customisation dialog can - show the "icons only" option on its choice of toolbar styles. */ - allowIconsWithTextChoice = 2, /**< If this flag is specified, the customisation dialog can - show the "icons with text" option on its choice of toolbar styles. */ - allowTextOnlyChoice = 4, /**< If this flag is specified, the customisation dialog can - show the "text only" option on its choice of toolbar styles. */ - showResetToDefaultsButton = 8, /**< If this flag is specified, the customisation dialog can - show a button to reset the toolbar to its default set of items. */ + /** The position of the slider's text-entry box. - allCustomisationOptionsEnabled = (allowIconsOnlyChoice | allowIconsWithTextChoice | allowTextOnlyChoice | showResetToDefaultsButton) + @see setTextBoxStyle + */ + enum TextEntryBoxPosition + { + NoTextBox, /**< Doesn't display a text box. */ + TextBoxLeft, /**< Puts the text box to the left of the slider, vertically centred. */ + TextBoxRight, /**< Puts the text box to the right of the slider, vertically centred. */ + TextBoxAbove, /**< Puts the text box above the slider, horizontally centred. */ + TextBoxBelow /**< Puts the text box below the slider, horizontally centred. */ }; - /** Pops up a modal dialog box that allows this toolbar to be customised by the user. - - The dialog contains a ToolbarItemPalette and various controls for editing other - aspects of the toolbar. This method will block and run the dialog box modally, - returning when the user closes it. - - The factory is used to determine the set of items that will be shown on the - palette. + /** Changes the location and properties of the text-entry box. - The optionFlags parameter is a bitwise-or of values from the CustomisationFlags - enum. + @param newPosition where it should go (or NoTextBox to not have one at all) + @param isReadOnly if true, it's a read-only display + @param textEntryBoxWidth the width of the text-box in pixels. Make sure this leaves enough + room for the slider as well! + @param textEntryBoxHeight the height of the text-box in pixels. Make sure this leaves enough + room for the slider as well! - @see ToolbarItemPalette + @see setTextBoxIsEditable, getValueFromText, getTextFromValue */ - void showCustomisationDialog (ToolbarItemFactory& factory, - const int optionFlags = allCustomisationOptionsEnabled); + void setTextBoxStyle (const TextEntryBoxPosition newPosition, + const bool isReadOnly, + const int textEntryBoxWidth, + const int textEntryBoxHeight); - /** Turns on or off the toolbar's editing mode, in which its items can be - rearranged by the user. + /** Returns the status of the text-box. + @see setTextBoxStyle + */ + const TextEntryBoxPosition getTextBoxPosition() const throw() { return textBoxPos; } - (In most cases it's easier just to use showCustomisationDialog() instead of - trying to enable editing directly). + /** Returns the width used for the text-box. + @see setTextBoxStyle + */ + int getTextBoxWidth() const throw() { return textBoxWidth; } - @see ToolbarItemPalette + /** Returns the height used for the text-box. + @see setTextBoxStyle */ - void setEditingActive (const bool editingEnabled); + int getTextBoxHeight() const throw() { return textBoxHeight; } - /** A set of colour IDs to use to change the colour of various aspects of the toolbar. + /** Makes the text-box editable. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + By default this is true, and the user can enter values into the textbox, + but it can be turned off if that's not suitable. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + @see setTextBoxStyle, getValueFromText, getTextFromValue */ - enum ColourIds - { - backgroundColourId = 0x1003200, /**< A colour to use to fill the toolbar's background. For - more control over this, override LookAndFeel::paintToolbarBackground(). */ - separatorColourId = 0x1003210, /**< A colour to use to draw the separator lines. */ - - buttonMouseOverBackgroundColourId = 0x1003220, /**< A colour used to paint the background of buttons when the mouse is - over them. */ - buttonMouseDownBackgroundColourId = 0x1003230, /**< A colour used to paint the background of buttons when the mouse is - held down on them. */ + void setTextBoxIsEditable (const bool shouldBeEditable) throw(); - labelTextColourId = 0x1003240, /**< A colour to use for drawing the text under buttons - when the style is set to iconsWithText or textOnly. */ + /** Returns true if the text-box is read-only. + @see setTextBoxStyle + */ + bool isTextBoxEditable() const throw() { return editableText; } - editingModeOutlineColourId = 0x1003250 /**< A colour to use for an outline around buttons when - the customisation dialog is active and the mouse moves over them. */ - }; + /** If the text-box is editable, this will give it the focus so that the user can + type directly into it. - /** Returns a string that represents the toolbar's current set of items. + This is basically the effect as the user clicking on it. + */ + void showTextBox(); - This lets you later restore the same item layout using restoreFromString(). + /** If the text-box currently has focus and is being edited, this resets it and takes keyboard + focus away from it. - @see restoreFromString + @param discardCurrentEditorContents if true, the slider's value will be left + unchanged; if false, the current contents of the + text editor will be used to set the slider position + before it is hidden. */ - const String toString() const; + void hideTextBox (const bool discardCurrentEditorContents); - /** Restores a set of items that was previously stored in a string by the toString() - method. + /** Changes the slider's current value. - The factory object is used to create any item components that are needed. + This will trigger a callback to SliderListener::sliderValueChanged() for any listeners + that are registered, and will synchronously call the valueChanged() method in case subclasses + want to handle it. - @see toString + @param newValue the new value to set - this will be restricted by the + minimum and maximum range, and will be snapped to the + nearest interval if one has been set + @param sendUpdateMessage if false, a change to the value will not trigger a call to + any SliderListeners or the valueChanged() method + @param sendMessageSynchronously if true, then a call to the SliderListeners will be made + synchronously; if false, it will be asynchronous */ - bool restoreFromString (ToolbarItemFactory& factoryToUse, - const String& savedVersion); - - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void buttonClicked (Button*); - /** @internal */ - void mouseDown (const MouseEvent&); - /** @internal */ - bool isInterestedInDragSource (const String&, Component*); - /** @internal */ - void itemDragMove (const String&, Component*, int, int); - /** @internal */ - void itemDragExit (const String&, Component*); - /** @internal */ - void itemDropped (const String&, Component*, int, int); - /** @internal */ - void updateAllItemPositions (const bool animate); - /** @internal */ - static ToolbarItemComponent* createItem (ToolbarItemFactory&, const int itemId); + void setValue (double newValue, + const bool sendUpdateMessage = true, + const bool sendMessageSynchronously = false); - juce_UseDebuggingNewOperator + /** Returns the slider's current value. */ + double getValue() const throw(); -private: - Button* missingItemsButton; - bool vertical, isEditingActive; - ToolbarItemStyle toolbarStyle; - ComponentAnimator animator; - friend class MissingItemsComponent; - Array items; + /** Sets the limits that the slider's value can take. - friend class ItemDragAndDropOverlayComponent; - static const tchar* const toolbarDragDescriptor; + @param newMinimum the lowest value allowed + @param newMaximum the highest value allowed + @param newInterval the steps in which the value is allowed to increase - if this + is not zero, the value will always be (newMinimum + (newInterval * an integer)). + */ + void setRange (const double newMinimum, + const double newMaximum, + const double newInterval = 0); - void addItemInternal (ToolbarItemFactory& factory, const int itemId, const int insertIndex); + /** Returns the current maximum value. + @see setRange + */ + double getMaximum() const throw() { return maximum; } - ToolbarItemComponent* getNextActiveComponent (int index, const int delta) const; + /** Returns the current minimum value. + @see setRange + */ + double getMinimum() const throw() { return minimum; } - Toolbar (const Toolbar&); - const Toolbar& operator= (const Toolbar&); -}; + /** Returns the current step-size for values. + @see setRange + */ + double getInterval() const throw() { return interval; } -#endif // __JUCE_TOOLBAR_JUCEHEADER__ -/********* End of inlined file: juce_Toolbar.h *********/ + /** For a slider with two or three thumbs, this returns the lower of its values. -class ItemDragAndDropOverlayComponent; + For a two-value slider, the values are controlled with getMinValue() and getMaxValue(). + A slider with three values also uses the normal getValue() and setValue() methods to + control the middle value. -/** - A component that can be used as one of the items in a Toolbar. + @see setMinValue, getMaxValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical + */ + double getMinValue() const throw(); - Each of the items on a toolbar must be a component derived from ToolbarItemComponent, - and these objects are always created by a ToolbarItemFactory - see the ToolbarItemFactory - class for further info about creating them. + /** For a slider with two or three thumbs, this sets the lower of its values. - The ToolbarItemComponent class is actually a button, but can be used to hold non-button - components too. To do this, set the value of isBeingUsedAsAButton to false when - calling the constructor, and override contentAreaChanged(), in which you can position - any sub-components you need to add. + This will trigger a callback to SliderListener::sliderValueChanged() for any listeners + that are registered, and will synchronously call the valueChanged() method in case subclasses + want to handle it. - To add basic buttons without writing a special subclass, have a look at the - ToolbarButton class. + @param newValue the new value to set - this will be restricted by the + minimum and maximum range, and will be snapped to the nearest + interval if one has been set. + @param sendUpdateMessage if false, a change to the value will not trigger a call to + any SliderListeners or the valueChanged() method + @param sendMessageSynchronously if true, then a call to the SliderListeners will be made + synchronously; if false, it will be asynchronous + @param allowNudgingOfOtherValues if false, this value will be restricted to being below the + max value (in a two-value slider) or the mid value (in a three-value + slider). If false, then if this value goes beyond those values, + it will push them along with it. + @see getMinValue, setMaxValue, setValue + */ + void setMinValue (double newValue, + const bool sendUpdateMessage = true, + const bool sendMessageSynchronously = false, + const bool allowNudgingOfOtherValues = false); - @see ToolbarButton, Toolbar, ToolbarItemFactory -*/ -class JUCE_API ToolbarItemComponent : public Button -{ -public: + /** For a slider with two or three thumbs, this returns the higher of its values. - /** Constructor. + For a two-value slider, the values are controlled with getMinValue() and getMaxValue(). + A slider with three values also uses the normal getValue() and setValue() methods to + control the middle value. - @param itemId the ID of the type of toolbar item which this represents - @param labelText the text to display if the toolbar's style is set to - Toolbar::iconsWithText or Toolbar::textOnly - @param isBeingUsedAsAButton set this to false if you don't want the button - to draw itself with button over/down states when the mouse - moves over it or clicks + @see getMinValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical */ - ToolbarItemComponent (const int itemId, - const String& labelText, - const bool isBeingUsedAsAButton); - - /** Destructor. */ - ~ToolbarItemComponent(); + double getMaxValue() const throw(); - /** Returns the item type ID that this component represents. - This value is in the constructor. - */ - int getItemId() const throw() { return itemId; } + /** For a slider with two or three thumbs, this sets the lower of its values. - /** Returns the toolbar that contains this component, or 0 if it's not currently - inside one. - */ - Toolbar* getToolbar() const; + This will trigger a callback to SliderListener::sliderValueChanged() for any listeners + that are registered, and will synchronously call the valueChanged() method in case subclasses + want to handle it. - /** Returns true if this component is currently inside a toolbar which is vertical. - @see Toolbar::isVertical + @param newValue the new value to set - this will be restricted by the + minimum and maximum range, and will be snapped to the nearest + interval if one has been set. + @param sendUpdateMessage if false, a change to the value will not trigger a call to + any SliderListeners or the valueChanged() method + @param sendMessageSynchronously if true, then a call to the SliderListeners will be made + synchronously; if false, it will be asynchronous + @param allowNudgingOfOtherValues if false, this value will be restricted to being above the + min value (in a two-value slider) or the mid value (in a three-value + slider). If false, then if this value goes beyond those values, + it will push them along with it. + @see getMaxValue, setMinValue, setValue */ - bool isToolbarVertical() const; + void setMaxValue (double newValue, + const bool sendUpdateMessage = true, + const bool sendMessageSynchronously = false, + const bool allowNudgingOfOtherValues = false); - /** Returns the current style setting of this item. + /** Adds a listener to be called when this slider's value changes. */ + void addListener (SliderListener* const listener) throw(); - Styles are listed in the Toolbar::ToolbarItemStyle enum. - @see setStyle, Toolbar::getStyle - */ - Toolbar::ToolbarItemStyle getStyle() const throw() { return toolbarStyle; } + /** Removes a previously-registered listener. */ + void removeListener (SliderListener* const listener) throw(); - /** Changes the current style setting of this item. + /** This lets you choose whether double-clicking moves the slider to a given position. - Styles are listed in the Toolbar::ToolbarItemStyle enum, and are automatically updated - by the toolbar that holds this item. + By default this is turned off, but it's handy if you want a double-click to act + as a quick way of resetting a slider. Just pass in the value you want it to + go to when double-clicked. - @see setStyle, Toolbar::setStyle + @see getDoubleClickReturnValue */ - virtual void setStyle (const Toolbar::ToolbarItemStyle& newStyle); + void setDoubleClickReturnValue (const bool isDoubleClickEnabled, + const double valueToSetOnDoubleClick) throw(); - /** Returns the area of the component that should be used to display the button image or - other contents of the item. + /** Returns the values last set by setDoubleClickReturnValue() method. - This content area may change when the item's style changes, and may leave a space around the - edge of the component where the text label can be shown. + Sets isEnabled to true if double-click is enabled, and returns the value + that was set. - @see contentAreaChanged + @see setDoubleClickReturnValue */ - const Rectangle getContentArea() const throw() { return contentArea; } + double getDoubleClickReturnValue (bool& isEnabled) const throw(); - /** This method must return the size criteria for this item, based on a given toolbar - size and orientation. + /** Tells the slider whether to keep sending change messages while the user + is dragging the slider. - The preferredSize, minSize and maxSize values must all be set by your implementation - method. If the toolbar is horizontal, these will be the width of the item; for a vertical - toolbar, they refer to the item's height. + If set to true, a change message will only be sent when the user has + dragged the slider and let go. If set to false (the default), then messages + will be continuously sent as they drag it while the mouse button is still + held down. + */ + void setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease) throw(); - The preferredSize is the size that the component would like to be, and this must be - between the min and max sizes. For a fixed-size item, simply set all three variables to - the same value. + /** This lets you change whether the slider thumb jumps to the mouse position + when you click. - The toolbarThickness parameter tells you the depth of the toolbar - the same as calling - Toolbar::getThickness(). + By default, this is true. If it's false, then the slider moves with relative + motion when you drag it. - The isToolbarVertical parameter tells you whether the bar is oriented horizontally or - vertically. + This only applies to linear bars, and won't affect two- or three- value + sliders. */ - virtual bool getToolbarItemSizes (int toolbarThickness, - bool isToolbarVertical, - int& preferredSize, - int& minSize, - int& maxSize) = 0; + void setSliderSnapsToMousePosition (const bool shouldSnapToMouse) throw(); - /** Your subclass should use this method to draw its content area. + /** If enabled, this gives the slider a pop-up bubble which appears while the + slider is being dragged. - The graphics object that is passed-in will have been clipped and had its origin - moved to fit the content area as specified get getContentArea(). The width and height - parameters are the width and height of the content area. + This can be handy if your slider doesn't have a text-box, so that users can + see the value just when they're changing it. - If the component you're writing isn't a button, you can just do nothing in this method. + If you pass a component as the parentComponentToUse parameter, the pop-up + bubble will be added as a child of that component when it's needed. If you + pass 0, the pop-up will be placed on the desktop instead (note that it's a + transparent window, so if you're using an OS that can't do transparent windows + you'll have to add it to a parent component instead). */ - virtual void paintButtonArea (Graphics& g, - int width, int height, - bool isMouseOver, bool isMouseDown) = 0; + void setPopupDisplayEnabled (const bool isEnabled, + Component* const parentComponentToUse) throw(); - /** Callback to indicate that the content area of this item has changed. + /** If this is set to true, then right-clicking on the slider will pop-up + a menu to let the user change the way it works. - This might be because the component was resized, or because the style changed and - the space needed for the text label is different. + By default this is turned off, but when turned on, the menu will include + things like velocity sensitivity, and for rotary sliders, whether they + use a linear or rotary mouse-drag to move them. + */ + void setPopupMenuEnabled (const bool menuEnabled) throw(); - See getContentArea() for a description of what the area is. + /** This can be used to stop the mouse scroll-wheel from moving the slider. + + By default it's enabled. */ - virtual void contentAreaChanged (const Rectangle& newBounds) = 0; + void setScrollWheelEnabled (const bool enabled) throw(); - /** Editing modes. - These are used by setEditingMode(), but will be rarely needed in user code. + /** Returns a number to indicate which thumb is currently being dragged by the + mouse. + + This will return 0 for the main thumb, 1 for the minimum-value thumb, 2 for + the maximum-value thumb, or -1 if none is currently down. */ - enum ToolbarEditingMode - { - normalMode = 0, /**< Means that the component is active, inside a toolbar. */ - editableOnToolbar, /**< Means that the component is on a toolbar, but the toolbar is in - customisation mode, and the items can be dragged around. */ - editableOnPalette /**< Means that the component is on an new-item palette, so it can be - dragged onto a toolbar to add it to that bar.*/ - }; + int getThumbBeingDragged() const throw() { return sliderBeingDragged; } - /** Changes the editing mode of this component. + /** Callback to indicate that the user is about to start dragging the slider. - This is used by the ToolbarItemPalette and related classes for making the items draggable, - and is unlikely to be of much use in end-user-code. + @see SliderListener::sliderDragStarted */ - void setEditingMode (const ToolbarEditingMode newMode); + virtual void startedDragging(); - /** Returns the current editing mode of this component. + /** Callback to indicate that the user has just stopped dragging the slider. - This is used by the ToolbarItemPalette and related classes for making the items draggable, - and is unlikely to be of much use in end-user-code. + @see SliderListener::sliderDragEnded */ - ToolbarEditingMode getEditingMode() const throw() { return mode; } + virtual void stoppedDragging(); - /** @internal */ - void paintButton (Graphics& g, bool isMouseOver, bool isMouseDown); - /** @internal */ - void resized(); + /** Callback to indicate that the user has just moved the slider. - juce_UseDebuggingNewOperator + @see SliderListener::sliderValueChanged + */ + virtual void valueChanged(); -private: - friend class Toolbar; - friend class ItemDragAndDropOverlayComponent; - const int itemId; - ToolbarEditingMode mode; - Toolbar::ToolbarItemStyle toolbarStyle; - Component* overlayComp; - int dragOffsetX, dragOffsetY; - bool isActive, isBeingDragged, isBeingUsedAsAButton; - Rectangle contentArea; + /** Callback to indicate that the user has just moved the slider. + Note - the valueChanged() method has changed its format and now no longer has + any parameters. Update your code to use the new version. + This version has been left here with an int as its return value to cause + a syntax error if you've got existing code that uses the old version. + */ + virtual int valueChanged (double) { jassertfalse; return 0; } - ToolbarItemComponent (const ToolbarItemComponent&); - const ToolbarItemComponent& operator= (const ToolbarItemComponent&); -}; + /** Subclasses can override this to convert a text string to a value. -#endif // __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ToolbarItemComponent.h *********/ + When the user enters something into the text-entry box, this method is + called to convert it to a value. -/** - A type of button designed to go on a toolbar. + The default routine just tries to convert it to a double. - This simple button can have two Drawable objects specified - one for normal - use and another one (optionally) for the button's "on" state if it's a - toggle button. + @see getTextFromValue + */ + virtual double getValueFromText (const String& text); - @see Toolbar, ToolbarItemFactory, ToolbarItemComponent, Drawable, Button -*/ -class JUCE_API ToolbarButton : public ToolbarItemComponent -{ -public: + /** Turns the slider's current value into a text string. - /** Creates a ToolbarButton. + Subclasses can override this to customise the formatting of the text-entry box. - @param itemId the ID for this toolbar item type. This is passed through to the - ToolbarItemComponent constructor - @param labelText the text to display on the button (if the toolbar is using a style - that shows text labels). This is passed through to the - ToolbarItemComponent constructor - @param normalImage a drawable object that the button should use as its icon. The object - that is passed-in here will be kept by this object and will be - deleted when no longer needed or when this button is deleted. - @param toggledOnImage a drawable object that the button can use as its icon if the button - is in a toggled-on state (see the Button::getToggleState() method). If - 0 is passed-in here, then the normal image will be used instead, regardless - of the toggle state. The object that is passed-in here will be kept by - this object and will be deleted when no longer needed or when this button - is deleted. + The default implementation just turns the value into a string, using + a number of decimal places based on the range interval. If a suffix string + has been set using setTextValueSuffix(), this will be appended to the text. + + @see getValueFromText */ - ToolbarButton (const int itemId, - const String& labelText, - Drawable* const normalImage, - Drawable* const toggledOnImage); + virtual const String getTextFromValue (double value); - /** Destructor. */ - ~ToolbarButton(); + /** Sets a suffix to append to the end of the numeric value when it's displayed as + a string. - /** @internal */ - bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, - int& minSize, int& maxSize); - /** @internal */ - void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown); - /** @internal */ - void contentAreaChanged (const Rectangle& newBounds); + This is used by the default implementation of getTextFromValue(), and is just + appended to the numeric value. For more advanced formatting, you can override + getTextFromValue() and do something else. + */ + void setTextValueSuffix (const String& suffix); - juce_UseDebuggingNewOperator + /** Allows a user-defined mapping of distance along the slider to its value. -private: - Drawable* const normalImage; - Drawable* const toggledOnImage; + The default implementation for this performs the skewing operation that + can be set up in the setSkewFactor() method. Override it if you need + some kind of custom mapping instead, but make sure you also implement the + inverse function in valueToProportionOfLength(). - ToolbarButton (const ToolbarButton&); - const ToolbarButton& operator= (const ToolbarButton&); -}; + @param proportion a value 0 to 1.0, indicating a distance along the slider + @returns the slider value that is represented by this position + @see valueToProportionOfLength + */ + virtual double proportionOfLengthToValue (double proportion); -#endif // __JUCE_TOOLBARBUTTON_JUCEHEADER__ -/********* End of inlined file: juce_ToolbarButton.h *********/ + /** Allows a user-defined mapping of value to the position of the slider along its length. -#endif -#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ + The default implementation for this performs the skewing operation that + can be set up in the setSkewFactor() method. Override it if you need + some kind of custom mapping instead, but make sure you also implement the + inverse function in proportionOfLengthToValue(). -#endif -#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ + @param value a valid slider value, between the range of values specified in + setRange() + @returns a value 0 to 1.0 indicating the distance along the slider that + represents this value + @see proportionOfLengthToValue + */ + virtual double valueToProportionOfLength (double value); -/********* Start of inlined file: juce_GlowEffect.h *********/ -#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ -#define __JUCE_GLOWEFFECT_JUCEHEADER__ + /** Returns the X or Y coordinate of a value along the slider's length. -/** - A component effect that adds a coloured blur around the component's contents. + If the slider is horizontal, this will be the X coordinate of the given + value, relative to the left of the slider. If it's vertical, then this will + be the Y coordinate, relative to the top of the slider. - (This will only work on non-opaque components). + If the slider is rotary, this will throw an assertion and return 0. If the + value is out-of-range, it will be constrained to the length of the slider. + */ + float getPositionOfValue (const double value); - @see Component::setComponentEffect, DropShadowEffect -*/ -class JUCE_API GlowEffect : public ImageEffectFilter -{ -public: + /** This can be overridden to allow the slider to snap to user-definable values. - /** Creates a default 'glow' effect. + If overridden, it will be called when the user tries to move the slider to + a given position, and allows a subclass to sanity-check this value, possibly + returning a different value to use instead. - To customise its appearance, use the setGlowProperties() method. + @param attemptedValue the value the user is trying to enter + @param userIsDragging true if the user is dragging with the mouse; false if + they are entering the value using the text box + @returns the value to use instead */ - GlowEffect(); + virtual double snapValue (double attemptedValue, const bool userIsDragging); - /** Destructor. */ - ~GlowEffect(); + /** This can be called to force the text box to update its contents. - /** Sets the glow's radius and colour. + (Not normally needed, as this is done automatically). + */ + void updateText(); - The radius is how large the blur should be, and the colour is - used to render it (for a less intense glow, lower the colour's - opacity). + /** True if the slider moves horizontally. */ + bool isHorizontal() const throw(); + /** True if the slider moves vertically. */ + bool isVertical() const throw(); + + /** A set of colour IDs to use to change the colour of various aspects of the slider. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void setGlowProperties (const float newRadius, - const Colour& newColour); + enum ColourIds + { + backgroundColourId = 0x1001200, /**< A colour to use to fill the slider's background. */ + thumbColourId = 0x1001300, /**< The colour to draw the thumb with. It's up to the look + and feel class how this is used. */ + trackColourId = 0x1001310, /**< The colour to draw the groove that the thumb moves along. */ + rotarySliderFillColourId = 0x1001311, /**< For rotary sliders, this colour fills the outer curve. */ + rotarySliderOutlineColourId = 0x1001312, /**< For rotary sliders, this colour is used to draw the outer curve's outline. */ - /** @internal */ - void applyEffect (Image& sourceImage, Graphics& destContext); + textBoxTextColourId = 0x1001400, /**< The colour for the text in the text-editor box used for editing the value. */ + textBoxBackgroundColourId = 0x1001500, /**< The background colour for the text-editor box. */ + textBoxHighlightColourId = 0x1001600, /**< The text highlight colour for the text-editor box. */ + textBoxOutlineColourId = 0x1001700 /**< The colour to use for a border around the text-editor box. */ + }; juce_UseDebuggingNewOperator +protected: + /** @internal */ + void labelTextChanged (Label*); + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseDoubleClick (const MouseEvent& e); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + void modifierKeysChanged (const ModifierKeys& modifiers); + /** @internal */ + void buttonClicked (Button* button); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + void enablementChanged(); + /** @internal */ + void focusOfChildComponentChanged (FocusChangeType cause); + /** @internal */ + void handleAsyncUpdate(); + /** @internal */ + void colourChanged(); + private: - float radius; - Colour colour; + SortedSet listeners; + double currentValue, valueMin, valueMax; + double minimum, maximum, interval, doubleClickReturnValue; + double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; + double velocityModeSensitivity, velocityModeOffset, minMaxDiff; + int velocityModeThreshold; + float rotaryStart, rotaryEnd; + int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; + int mouseDragStartX, mouseDragStartY; + int sliderRegionStart, sliderRegionSize; + int sliderBeingDragged; + int pixelsForFullDragExtent; + Rectangle sliderRect; + String textSuffix; + + SliderStyle style; + TextEntryBoxPosition textBoxPos; + int textBoxWidth, textBoxHeight; + IncDecButtonMode incDecButtonMode; + + bool editableText : 1, doubleClickToValue : 1; + bool isVelocityBased : 1, userKeyOverridesVelocity : 1, rotaryStop : 1; + bool incDecButtonsSideBySide : 1, sendChangeOnlyOnRelease : 1, popupDisplayEnabled : 1; + bool menuEnabled : 1, menuShown : 1, mouseWasHidden : 1, incDecDragged : 1; + bool scrollWheelEnabled : 1, snapsToMousePos : 1; + Font font; + Label* valueBox; + Button* incButton; + Button* decButton; + Component* popupDisplay; + Component* parentForPopupDisplay; + + float getLinearSliderPos (const double value); + void restoreMouseIfHidden(); + void sendDragStart(); + void sendDragEnd(); + double constrainedValue (double value) const throw(); + void triggerChangeMessage (const bool synchronous); + bool incDecDragDirectionIsHorizontal() const throw(); + + Slider (const Slider&); + const Slider& operator= (const Slider&); }; -#endif // __JUCE_GLOWEFFECT_JUCEHEADER__ -/********* End of inlined file: juce_GlowEffect.h *********/ +#endif // __JUCE_SLIDER_JUCEHEADER__ +/********* End of inlined file: juce_Slider.h *********/ #endif -#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ +#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ #endif -#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ +#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ReduceOpacityEffect.h *********/ -#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ -#define __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ +/********* Start of inlined file: juce_TableHeaderComponent.h *********/ +#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ +#define __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ + +class TableHeaderComponent; /** - An effect filter that reduces the image's opacity. + Receives events from a TableHeaderComponent when columns are resized, moved, etc. - This can be used to make a component (and its child components) more - transparent. + You can register one of these objects for table events using TableHeaderComponent::addListener() + and TableHeaderComponent::removeListener(). - @see Component::setComponentEffect + @see TableHeaderComponent */ -class JUCE_API ReduceOpacityEffect : public ImageEffectFilter +class JUCE_API TableHeaderListener { public: - /** Creates the effect object. - - The opacity of the component to which the effect is applied will be - scaled by the given factor (in the range 0 to 1.0f). - */ - ReduceOpacityEffect (const float opacity = 1.0f); + TableHeaderListener() {} /** Destructor. */ - ~ReduceOpacityEffect(); + virtual ~TableHeaderListener() {} - /** Sets how much to scale the component's opacity. + /** This is called when some of the table's columns are added, removed, hidden, + or rearranged. + */ + virtual void tableColumnsChanged (TableHeaderComponent* tableHeader) = 0; - @param newOpacity should be between 0 and 1.0f + /** This is called when one or more of the table's columns are resized. */ - void setOpacity (const float newOpacity); + virtual void tableColumnsResized (TableHeaderComponent* tableHeader) = 0; - /** @internal */ - void applyEffect (Image& sourceImage, Graphics& destContext); + /** This is called when the column by which the table should be sorted is changed. + */ + virtual void tableSortOrderChanged (TableHeaderComponent* tableHeader) = 0; - juce_UseDebuggingNewOperator + /** This is called when the user begins or ends dragging one of the columns around. -private: - float opacity; + When the user starts dragging a column, this is called with the ID of that + column. When they finish dragging, it is called again with 0 as the ID. + */ + virtual void tableColumnDraggingChanged (TableHeaderComponent* tableHeader, + int columnIdNowBeingDragged); }; -#endif // __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ -/********* End of inlined file: juce_ReduceOpacityEffect.h *********/ - -#endif -#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ - -#endif -#ifndef __JUCE_KEYPRESS_JUCEHEADER__ +/** + A component that displays a strip of column headings for a table, and allows these + to be resized, dragged around, etc. -#endif -#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ + This is just the component that goes at the top of a table. You can use it + directly for custom components, or to create a simple table, use the + TableListBox class. -/********* Start of inlined file: juce_KeyPressMappingSet.h *********/ -#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ -#define __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ + To use one of these, create it and use addColumn() to add all the columns that you need. + Each column must be given a unique ID number that's used to refer to it. -/** - Manages and edits a list of keypresses, which it uses to invoke the appropriate - command in a ApplicationCommandManager. + @see TableListBox, TableHeaderListener +*/ +class JUCE_API TableHeaderComponent : public Component, + private AsyncUpdater +{ +public: - Normally, you won't actually create a KeyPressMappingSet directly, because - each ApplicationCommandManager contains its own KeyPressMappingSet, so typically - you'd create yourself an ApplicationCommandManager, and call its - ApplicationCommandManager::getKeyMappings() method to get a pointer to its - KeyPressMappingSet. + /** Creates an empty table header. + */ + TableHeaderComponent(); - For one of these to actually use keypresses, you'll need to add it as a KeyListener - to the top-level component for which you want to handle keystrokes. So for example: + /** Destructor. */ + ~TableHeaderComponent(); - @code - class MyMainWindow : public Component + /** A combination of these flags are passed into the addColumn() method to specify + the properties of a column. + */ + enum ColumnPropertyFlags { - ApplicationCommandManager* myCommandManager; + visible = 1, /**< If this is set, the column will be shown; if not, it will be hidden until the user enables it with the pop-up menu. */ + resizable = 2, /**< If this is set, the column can be resized by dragging it. */ + draggable = 4, /**< If this is set, the column can be dragged around to change its order in the table. */ + appearsOnColumnMenu = 8, /**< If this is set, the column will be shown on the pop-up menu allowing it to be hidden/shown. */ + sortable = 16, /**< If this is set, then clicking on the column header will set it to be the sort column, and clicking again will reverse the order. */ + sortedForwards = 32, /**< If this is set, the column is currently the one by which the table is sorted (forwards). */ + sortedBackwards = 64, /**< If this is set, the column is currently the one by which the table is sorted (backwards). */ - public: - MyMainWindow() - { - myCommandManager = new ApplicationCommandManager(); + /** This set of default flags is used as the default parameter value in addColumn(). */ + defaultFlags = (visible | resizable | draggable | appearsOnColumnMenu | sortable), - // first, make sure the command manager has registered all the commands that its - // targets can perform.. - myCommandManager->registerAllCommandsForTarget (myCommandTarget1); - myCommandManager->registerAllCommandsForTarget (myCommandTarget2); + /** A quick way of combining flags for a column that's not resizable. */ + notResizable = (visible | draggable | appearsOnColumnMenu | sortable), - // this will use the command manager to initialise the KeyPressMappingSet with - // the default keypresses that were specified when the targets added their commands - // to the manager. - myCommandManager->getKeyMappings()->resetToDefaultMappings(); + /** A quick way of combining flags for a column that's not resizable or sortable. */ + notResizableOrSortable = (visible | draggable | appearsOnColumnMenu), - // having set up the default key-mappings, you might now want to load the last set - // of mappings that the user configured. - myCommandManager->getKeyMappings()->restoreFromXml (lastSavedKeyMappingsXML); - - // Now tell our top-level window to send any keypresses that arrive to the - // KeyPressMappingSet, which will use them to invoke the appropriate commands. - addKeyListener (myCommandManager->getKeyMappings()); - } - - ... - } - @endcode + /** A quick way of combining flags for a column that's not sortable. */ + notSortable = (visible | resizable | draggable | appearsOnColumnMenu) + }; - KeyPressMappingSet derives from ChangeBroadcaster so that interested parties can - register to be told when a command or mapping is added, removed, etc. + /** Adds a column to the table. - There's also a UI component called KeyMappingEditorComponent that can be used - to easily edit the key mappings. + This will add a column, and asynchronously call the tableColumnsChanged() method of any + registered listeners. - @see Component::addKeyListener(), KeyMappingEditorComponent, ApplicationCommandManager -*/ -class JUCE_API KeyPressMappingSet : public KeyListener, - public ChangeBroadcaster, - public FocusChangeListener -{ -public: + @param columnName the name of the new column. It's ok to have two or more columns with the same name + @param columnId an ID for this column. The ID can be any number apart from 0, but every column must have + a unique ID. This is used to identify the column later on, after the user may have + changed the order that they appear in + @param width the initial width of the column, in pixels + @param maximumWidth a maximum width that the column can take when the user is resizing it. This only applies + if the 'resizable' flag is specified for this column + @param minimumWidth a minimum width that the column can take when the user is resizing it. This only applies + if the 'resizable' flag is specified for this column + @param propertyFlags a combination of some of the values from the ColumnPropertyFlags enum, to define the + properties of this column + @param insertIndex the index at which the column should be added. A value of 0 puts it at the start (left-hand side) + and -1 puts it at the end (right-hand size) of the table. Note that the index the index within + all columns, not just the index amongst those that are currently visible + */ + void addColumn (const String& columnName, + const int columnId, + const int width, + const int minimumWidth = 30, + const int maximumWidth = -1, + const int propertyFlags = defaultFlags, + const int insertIndex = -1); - /** Creates a KeyPressMappingSet for a given command manager. + /** Removes a column with the given ID. - Normally, you won't actually create a KeyPressMappingSet directly, because - each ApplicationCommandManager contains its own KeyPressMappingSet, so the - best thing to do is to create your ApplicationCommandManager, and use the - ApplicationCommandManager::getKeyMappings() method to access its mappings. + If there is such a column, this will asynchronously call the tableColumnsChanged() method of any + registered listeners. + */ + void removeColumn (const int columnIdToRemove); - When a suitable keypress happens, the manager's invoke() method will be - used to invoke the appropriate command. + /** Deletes all columns from the table. - @see ApplicationCommandManager + If there are any columns to remove, this will asynchronously call the tableColumnsChanged() method of any + registered listeners. */ - KeyPressMappingSet (ApplicationCommandManager* const commandManager) throw(); - - /** Creates an copy of a KeyPressMappingSet. */ - KeyPressMappingSet (const KeyPressMappingSet& other) throw(); + void removeAllColumns(); - /** Destructor. */ - ~KeyPressMappingSet(); + /** Returns the number of columns in the table. - ApplicationCommandManager* getCommandManager() const throw() { return commandManager; } + If onlyCountVisibleColumns is true, this will return the number of visible columns; otherwise it'll + return the total number of columns, including hidden ones. - /** Returns a list of keypresses that are assigned to a particular command. + @see isColumnVisible + */ + int getNumColumns (const bool onlyCountVisibleColumns) const throw(); - @param commandID the command's ID + /** Returns the name for a column. + @see setColumnName */ - const Array getKeyPressesAssignedToCommand (const CommandID commandID) const throw(); + const String getColumnName (const int columnId) const throw(); - /** Assigns a keypress to a command. + /** Changes the name of a column. */ + void setColumnName (const int columnId, const String& newName); - If the keypress is already assigned to a different command, it will first be - removed from that command, to avoid it triggering multiple functions. + /** Moves a column to a different index in the table. - @param commandID the ID of the command that you want to add a keypress to. If - this is 0, the keypress will be removed from anything that it - was previously assigned to, but not re-assigned - @param newKeyPress the new key-press - @param insertIndex if this is less than zero, the key will be appended to the - end of the list of keypresses; otherwise the new keypress will - be inserted into the existing list at this index + @param columnId the column to move + @param newVisibleIndex the target index for it, from 0 to the number of columns currently visible. */ - void addKeyPress (const CommandID commandID, - const KeyPress& newKeyPress, - int insertIndex = -1) throw(); + void moveColumn (const int columnId, int newVisibleIndex); - /** Reset all mappings to the defaults, as dictated by the ApplicationCommandManager. + /** Returns the width of one of the columns. + */ + int getColumnWidth (const int columnId) const throw(); - @see resetToDefaultMapping + /** Changes the width of a column. + + This will cause an asynchronous callback to the tableColumnsResized() method of any registered listeners. */ - void resetToDefaultMappings() throw(); + void setColumnWidth (const int columnId, const int newWidth); - /** Resets all key-mappings to the defaults for a particular command. + /** Shows or hides a column. - @see resetToDefaultMappings + This can cause an asynchronous callback to the tableColumnsChanged() method of any registered listeners. + @see isColumnVisible */ - void resetToDefaultMapping (const CommandID commandID) throw(); + void setColumnVisible (const int columnId, const bool shouldBeVisible); - /** Removes all keypresses that are assigned to any commands. */ - void clearAllKeyPresses() throw(); + /** Returns true if this column is currently visible. + @see setColumnVisible + */ + bool isColumnVisible (const int columnId) const; - /** Removes all keypresses that are assigned to a particular command. */ - void clearAllKeyPresses (const CommandID commandID) throw(); + /** Changes the column which is the sort column. - /** Removes one of the keypresses that are assigned to a command. + This can cause an asynchronous callback to the tableSortOrderChanged() method of any registered listeners. - See the getKeyPressesAssignedToCommand() for the list of keypresses to - which the keyPressIndex refers. - */ - void removeKeyPress (const CommandID commandID, - const int keyPressIndex) throw(); + If this method doesn't actually change the column ID, then no re-sort will take place (you can + call reSortTable() to force a re-sort to happen if you've modified the table's contents). - /** Removes a keypress from any command that it may be assigned to. + @see getSortColumnId, isSortedForwards, reSortTable */ - void removeKeyPress (const KeyPress& keypress) throw(); - - /** Returns true if the given command is linked to this key. */ - bool containsMapping (const CommandID commandID, - const KeyPress& keyPress) const throw(); + void setSortColumnId (const int columnId, const bool sortForwards); - /** Looks for a command that corresponds to a keypress. + /** Returns the column ID by which the table is currently sorted, or 0 if it is unsorted. - @returns the UID of the command or 0 if none was found + @see setSortColumnId, isSortedForwards */ - CommandID findCommandForKeyPress (const KeyPress& keyPress) const throw(); + int getSortColumnId() const throw(); - /** Tries to recreate the mappings from a previously stored state. + /** Returns true if the table is currently sorted forwards, or false if it's backwards. + @see setSortColumnId + */ + bool isSortedForwards() const throw(); - The XML passed in must have been created by the createXml() method. + /** Triggers a re-sort of the table according to the current sort-column. - If the stored state makes any reference to commands that aren't - currently available, these will be ignored. + If you modifiy the table's contents, you can call this to signal that the table needs + to be re-sorted. - If the set of mappings being loaded was a set of differences (using createXml (true)), - then this will call resetToDefaultMappings() and then merge the saved mappings - on top. If the saved set was created with createXml (false), then this method - will first clear all existing mappings and load the saved ones as a complete set. + (This doesn't do any sorting synchronously - it just asynchronously sends a call to the + tableSortOrderChanged() method of any listeners). + */ + void reSortTable(); - @returns true if it manages to load the XML correctly - @see createXml + /** Returns the total width of all the visible columns in the table. */ - bool restoreFromXml (const XmlElement& xmlVersion); + int getTotalWidth() const throw(); - /** Creates an XML representation of the current mappings. + /** Returns the index of a given column. - This will produce a lump of XML that can be later reloaded using - restoreFromXml() to recreate the current mapping state. + If there's no such column ID, this will return -1. - The object that is returned must be deleted by the caller. + If onlyCountVisibleColumns is true, this will return the index amoungst the visible columns; + otherwise it'll return the index amongst all the columns, including any hidden ones. + */ + int getIndexOfColumnId (const int columnId, const bool onlyCountVisibleColumns) const throw(); - @param saveDifferencesFromDefaultSet if this is false, then all keypresses - will be saved into the XML. If it's true, then the XML will - only store the differences between the current mappings and - the default mappings you'd get from calling resetToDefaultMappings(). - The advantage of saving a set of differences from the default is that - if you change the default mappings (in a new version of your app, for - example), then these will be merged into a user's saved preferences. + /** Returns the ID of the column at a given index. - @see restoreFromXml + If onlyCountVisibleColumns is true, this will count the index amoungst the visible columns; + otherwise it'll count it amongst all the columns, including any hidden ones. + + If the index is out-of-range, it'll return 0. */ - XmlElement* createXml (const bool saveDifferencesFromDefaultSet) const; + int getColumnIdOfIndex (int index, const bool onlyCountVisibleColumns) const throw(); - /** @internal */ - bool keyPressed (const KeyPress& key, Component* originatingComponent); - /** @internal */ - bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); - /** @internal */ - void globalFocusChanged (Component* focusedComponent); + /** Returns the rectangle containing of one of the columns. - juce_UseDebuggingNewOperator + The index is an index from 0 to the number of columns that are currently visible (hidden + ones are not counted). It returns a rectangle showing the position of the column relative + to this component's top-left. If the index is out-of-range, an empty rectangle is retrurned. + */ + const Rectangle getColumnPosition (const int index) const throw(); -private: + /** Finds the column ID at a given x-position in the component. - ApplicationCommandManager* commandManager; + If there is a column at this point this returns its ID, or if not, it will return 0. + */ + int getColumnIdAtX (const int xToFind) const throw(); - struct CommandMapping - { - CommandID commandID; - Array keypresses; - bool wantsKeyUpDownCallbacks; - }; + /** If set to true, this indicates that the columns should be expanded or shrunk to fill the + entire width of the component. - OwnedArray mappings; + By default this is disabled. Turning it on also means that when resizing a column, those + on the right will be squashed to fit. + */ + void setStretchToFitActive (const bool shouldStretchToFit); - struct KeyPressTime - { - KeyPress key; - uint32 timeWhenPressed; - }; + /** Returns true if stretch-to-fit has been enabled. + @see setStretchToFitActive + */ + bool isStretchToFitActive() const throw(); - OwnedArray keysDown; + /** If stretch-to-fit is enabled, this will resize all the columns to make them fit into the + specified width, keeping their relative proportions the same. - void handleMessage (const Message& message); + If the minimum widths of the columns are too wide to fit into this space, it may + actually end up wider. + */ + void resizeAllColumnsToFit (int targetTotalWidth); - void invokeCommand (const CommandID commandID, - const KeyPress& keyPress, - const bool isKeyDown, - const int millisecsSinceKeyPressed, - Component* const originatingComponent) const; + /** Enables or disables the pop-up menu. - const KeyPressMappingSet& operator= (const KeyPressMappingSet&); -}; + The default menu allows the user to show or hide columns. You can add custom + items to this menu by overloading the addMenuItems() and reactToMenuItem() methods. -#endif // __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ -/********* End of inlined file: juce_KeyPressMappingSet.h *********/ + By default the menu is enabled. -#endif -#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ + @see isPopupMenuActive, addMenuItems, reactToMenuItem + */ + void setPopupMenuActive (const bool hasMenu); -#endif -#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ + /** Returns true if the pop-up menu is enabled. + @see setPopupMenuActive + */ + bool isPopupMenuActive() const throw(); -#endif -#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ + /** Returns a string that encapsulates the table's current layout. -/********* Start of inlined file: juce_KeyMappingEditorComponent.h *********/ -#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ -#define __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ + This can be restored later using restoreFromString(). It saves the order of + the columns, the currently-sorted column, and the widths. -/********* Start of inlined file: juce_TreeView.h *********/ -#ifndef __JUCE_TREEVIEW_JUCEHEADER__ -#define __JUCE_TREEVIEW_JUCEHEADER__ + @see restoreFromString + */ + const String toString() const; -/********* Start of inlined file: juce_FileDragAndDropTarget.h *********/ -#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ -#define __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ + /** Restores the state of the table, based on a string previously created with + toString(). -/** - Components derived from this class can have files dropped onto them by an external application. + @see toString + */ + void restoreFromString (const String& storedVersion); - @see DragAndDropContainer -*/ -class JUCE_API FileDragAndDropTarget -{ -public: - /** Destructor. */ - virtual ~FileDragAndDropTarget() {} + /** Adds a listener to be informed about things that happen to the header. */ + void addListener (TableHeaderListener* const newListener) throw(); - /** Callback to check whether this target is interested in the set of files being offered. + /** Removes a previously-registered listener. */ + void removeListener (TableHeaderListener* const listenerToRemove) throw(); - Note that this will be called repeatedly when the user is dragging the mouse around over your - component, so don't do anything time-consuming in here, like opening the files to have a look - inside them! + /** This can be overridden to handle a mouse-click on one of the column headers. - @param files the set of (absolute) pathnames of the files that the user is dragging - @returns true if this component wants to receive the other callbacks regarging this - type of object; if it returns false, no other callbacks will be made. + The default implementation will use this click to call getSortColumnId() and + change the sort order. */ - virtual bool isInterestedInFileDrag (const StringArray& files) = 0; + virtual void columnClicked (int columnId, const ModifierKeys& mods); - /** Callback to indicate that some files are being dragged over this component. + /** This can be overridden to add custom items to the pop-up menu. - This gets called when the user moves the mouse into this component while dragging. + If you override this, you should call the superclass's method to add its + column show/hide items, if you want them on the menu as well. - Use this callback as a trigger to make your component repaint itself to give the - user feedback about whether the files can be dropped here or not. + Then to handle the result, override reactToMenuItem(). - @param files the set of (absolute) pathnames of the files that the user is dragging - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component + @see reactToMenuItem */ - virtual void fileDragEnter (const StringArray& files, int x, int y); + virtual void addMenuItems (PopupMenu& menu, const int columnIdClicked); - /** Callback to indicate that the user is dragging some files over this component. + /** Override this to handle any custom items that you have added to the + pop-up menu with an addMenuItems() override. - This gets called when the user moves the mouse over this component while dragging. - Normally overriding itemDragEnter() and itemDragExit() are enough, but - this lets you know what happens in-between. + If the menuReturnId isn't one of your own custom menu items, you'll need to + call TableHeaderComponent::reactToMenuItem() to allow the base class to + handle the items that it had added. - @param files the set of (absolute) pathnames of the files that the user is dragging - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component + @see addMenuItems */ - virtual void fileDragMove (const StringArray& files, int x, int y); + virtual void reactToMenuItem (const int menuReturnId, const int columnIdClicked); - /** Callback to indicate that the mouse has moved away from this component. + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void mouseMove (const MouseEvent&); + /** @internal */ + void mouseEnter (const MouseEvent&); + /** @internal */ + void mouseExit (const MouseEvent&); + /** @internal */ + void mouseDown (const MouseEvent&); + /** @internal */ + void mouseDrag (const MouseEvent&); + /** @internal */ + void mouseUp (const MouseEvent&); + /** @internal */ + const MouseCursor getMouseCursor(); - This gets called when the user moves the mouse out of this component while dragging - the files. + /** Can be overridden for more control over the pop-up menu behaviour. */ + virtual void showColumnChooserMenu (const int columnIdClicked); - If you've used fileDragEnter() to repaint your component and give feedback, use this - as a signal to repaint it in its normal state. + juce_UseDebuggingNewOperator - @param files the set of (absolute) pathnames of the files that the user is dragging - */ - virtual void fileDragExit (const StringArray& files); +private: + struct ColumnInfo + { + String name; + int id, propertyFlags, width, minimumWidth, maximumWidth; + double lastDeliberateWidth; - /** Callback to indicate that the user has dropped the files onto this component. + bool isVisible() const throw(); + }; - When the user drops the files, this get called, and you can use the files in whatever - way is appropriate. + OwnedArray columns; + Array listeners; + Component* dragOverlayComp; - Note that after this is called, the fileDragExit method may not be called, so you should - clean up in here if there's anything you need to do when the drag finishes. + bool columnsChanged, columnsResized, sortChanged, menuActive, stretchToFit; + int columnIdBeingResized, columnIdBeingDragged, initialColumnWidth; + int columnIdUnderMouse, draggingColumnOffset, draggingColumnOriginalIndex, lastDeliberateWidth; - @param files the set of (absolute) pathnames of the files that the user is dragging - @param x the mouse x position, relative to this component - @param y the mouse y position, relative to this component - */ - virtual void filesDropped (const StringArray& files, int x, int y) = 0; + ColumnInfo* getInfoForId (const int columnId) const throw(); + int visibleIndexToTotalIndex (const int visibleIndex) const throw(); + void sendColumnsChanged(); + void handleAsyncUpdate(); + void beginDrag (const MouseEvent&); + void endDrag (const int finalIndex); + int getResizeDraggerAt (const int mouseX) const throw(); + void updateColumnUnderMouse (int x, int y); + void resizeColumnsToFit (int firstColumnIndex, int targetTotalWidth); + + TableHeaderComponent (const TableHeaderComponent&); + const TableHeaderComponent operator= (const TableHeaderComponent&); }; -#endif // __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ -/********* End of inlined file: juce_FileDragAndDropTarget.h *********/ +#endif // __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_TableHeaderComponent.h *********/ -class TreeView; +#endif +#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ + +/********* Start of inlined file: juce_TableListBox.h *********/ +#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ +#define __JUCE_TABLELISTBOX_JUCEHEADER__ /** - An item in a treeview. + One of these is used by a TableListBox as the data model for the table's contents. - A TreeViewItem can either be a leaf-node in the tree, or it can contain its - own sub-items. + The virtual methods that you override in this class take care of drawing the + table cells, and reacting to events. - To implement an item that contains sub-items, override the itemOpennessChanged() - method so that when it is opened, it adds the new sub-items to itself using the - addSubItem method. Depending on the nature of the item it might choose to only - do this the first time it's opened, or it might want to refresh itself each time. - It also has the option of deleting its sub-items when it is closed, or leaving them - in place. + @see TableListBox */ -class JUCE_API TreeViewItem +class JUCE_API TableListBoxModel { public: - /** Constructor. */ - TreeViewItem(); + TableListBoxModel() {} /** Destructor. */ - virtual ~TreeViewItem(); - - /** Returns the number of sub-items that have been added to this item. + virtual ~TableListBoxModel() {} - Note that this doesn't mean much if the node isn't open. + /** This must return the number of rows currently in the table. - @see getSubItem, mightContainSubItems, addSubItem + If the number of rows changes, you must call TableListBox::updateContent() to + cause it to refresh the list. */ - int getNumSubItems() const throw(); - - /** Returns one of the item's sub-items. + virtual int getNumRows() = 0; - Remember that the object returned might get deleted at any time when its parent - item is closed or refreshed, depending on the nature of the items you're using. + /** This must draw the background behind one of the rows in the table. - @see getNumSubItems + The graphics context has its origin at the row's top-left, and your method + should fill the area specified by the width and height parameters. */ - TreeViewItem* getSubItem (const int index) const throw(); - - /** Removes any sub-items. */ - void clearSubItems(); + virtual void paintRowBackground (Graphics& g, + int rowNumber, + int width, int height, + bool rowIsSelected) = 0; - /** Adds a sub-item. + /** This must draw one of the cells. - @param newItem the object to add to the item's sub-item list. Once added, these can be - found using getSubItem(). When the items are later removed with - removeSubItem() (or when this item is deleted), they will be deleted. - @param insertPosition the index which the new item should have when it's added. If this - value is less than 0, the item will be added to the end of the list. + The graphics context's origin will already be set to the top-left of the cell, + whose size is specified by (width, height). */ - void addSubItem (TreeViewItem* const newItem, - const int insertPosition = -1); - - /** Removes one of the sub-items. + virtual void paintCell (Graphics& g, + int rowNumber, + int columnId, + int width, int height, + bool rowIsSelected) = 0; - @param index the item to remove - @param deleteItem if true, the item that is removed will also be deleted. - */ - void removeSubItem (const int index, - const bool deleteItem = true); + /** This is used to create or update a custom component to go in a cell. - /** Returns the TreeView to which this item belongs. */ - TreeView* getOwnerView() const throw() { return ownerView; } + Any cell may contain a custom component, or can just be drawn with the paintCell() method + and handle mouse clicks with cellClicked(). - /** Returns the item within which this item is contained. */ - TreeViewItem* getParentItem() const throw() { return parentItem; } + This method will be called whenever a custom component might need to be updated - e.g. + when the table is changed, or TableListBox::updateContent() is called. - /** True if this item is currently open in the treeview. */ - bool isOpen() const throw(); + If you don't need a custom component for the specified cell, then return 0. - /** Opens or closes the item. + If you do want a custom component, and the existingComponentToUpdate is null, then + this method must create a new component suitable for the cell, and return it. - When opened or closed, the item's itemOpennessChanged() method will be called, - and a subclass should use this callback to create and add any sub-items that - it needs to. - - @see itemOpennessChanged, mightContainSubItems + If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created + by this method. In this case, the method must either update it to make sure it's correctly representing + the given cell (which may be different from the one that the component was created for), or it can + delete this component and return a new one. */ - void setOpen (const bool shouldBeOpen); + virtual Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected, + Component* existingComponentToUpdate); - /** True if this item is currently selected. + /** This callback is made when the user clicks on one of the cells in the table. - Use this when painting the node, to decide whether to draw it as selected or not. + The mouse event's coordinates will be relative to the entire table row. + @see cellDoubleClicked, backgroundClicked */ - bool isSelected() const throw(); + virtual void cellClicked (int rowNumber, int columnId, const MouseEvent& e); - /** Selects or deselects the item. + /** This callback is made when the user clicks on one of the cells in the table. - This will cause a callback to itemSelectionChanged() + The mouse event's coordinates will be relative to the entire table row. + @see cellClicked, backgroundClicked */ - void setSelected (const bool shouldBeSelected, - const bool deselectOtherItemsFirst); + virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent& e); - /** Returns the rectangle that this item occupies. + /** This can be overridden to react to the user double-clicking on a part of the list where + there are no rows. - If relativeToTreeViewTopLeft is true, the co-ordinates are relative to the - top-left of the TreeView comp, so this will depend on the scroll-position of - the tree. If false, it is relative to the top-left of the topmost item in the - tree (so this would be unaffected by scrolling the view). + @see cellClicked */ - const Rectangle getItemPosition (const bool relativeToTreeViewTopLeft) const throw(); + virtual void backgroundClicked(); - /** Sends a signal to the treeview to make it refresh itself. + /** This callback is made when the table's sort order is changed. - Call this if your items have changed and you want the tree to update to reflect - this. + This could be because the user has clicked a column header, or because the + TableHeaderComponent::setSortColumnId() method was called. + + If you implement this, your method should re-sort the table using the given + column as the key. */ - void treeHasChanged() const throw(); + virtual void sortOrderChanged (int newSortColumnId, const bool isForwards); - /** Sends a repaint message to redraw just this item. + /** Returns the best width for one of the columns. - Note that you should only call this if you want to repaint a superficial change. If - you're altering the tree's nodes, you should instead call treeHasChanged(). - */ - void repaintItem() const; + If you implement this method, you should measure the width of all the items + in this column, and return the best size. - /** Returns the row number of this item in the tree. + Returning 0 means that the column shouldn't be changed. - The row number of an item will change according to which items are open. + This is used by TableListBox::autoSizeColumn() and TableListBox::autoSizeAllColumns(). + */ + virtual int getColumnAutoSizeWidth (int columnId); - @see TreeView::getNumRowsInTree(), TreeView::getItemOnRow() + /** Returns a tooltip for a particular cell in the table. */ - int getRowNumberInTree() const throw(); + virtual const String getCellTooltip (int rowNumber, int columnId); - /** Returns true if all the item's parent nodes are open. + /** Override this to be informed when rows are selected or deselected. - This is useful to check whether the item might actually be visible or not. + @see ListBox::selectedRowsChanged() */ - bool areAllParentsOpen() const throw(); + virtual void selectedRowsChanged (int lastRowSelected); - /** Changes whether lines are drawn to connect any sub-items to this item. + /** Override this to be informed when the delete key is pressed. - By default, line-drawing is turned on. + @see ListBox::deleteKeyPressed() */ - void setLinesDrawnForSubItems (const bool shouldDrawLines) throw(); + virtual void deleteKeyPressed (int lastRowSelected); - /** Tells the tree whether this item can potentially be opened. + /** Override this to be informed when the return key is pressed. - If your item could contain sub-items, this should return true; if it returns - false then the tree will not try to open the item. This determines whether or - not the item will be drawn with a 'plus' button next to it. + @see ListBox::returnKeyPressed() */ - virtual bool mightContainSubItems() = 0; - - /** Returns a string to uniquely identify this item. + virtual void returnKeyPressed (int lastRowSelected); - If you're planning on using the TreeView::getOpennessState() method, then - these strings will be used to identify which nodes are open. The string - should be unique amongst the item's sibling items, but it's ok for there - to be duplicates at other levels of the tree. + /** Override this to be informed when the list is scrolled. - If you're not going to store the state, then it's ok not to bother implementing - this method. + This might be caused by the user moving the scrollbar, or by programmatic changes + to the list position. */ - virtual const String getUniqueName() const; + virtual void listWasScrolled(); - /** Called when an item is opened or closed. + /** To allow rows from your table to be dragged-and-dropped, implement this method. - When setOpen() is called and the item has specified that it might - have sub-items with the mightContainSubItems() method, this method - is called to let the item create or manage its sub-items. + If this returns a non-empty name then when the user drags a row, the table will try to + find a DragAndDropContainer in its parent hierarchy, and will use it to trigger a + drag-and-drop operation, using this string as the source description, and the listbox + itself as the source component. - So when this is called with isNowOpen set to true (i.e. when the item is being - opened), a subclass might choose to use clearSubItems() and addSubItem() to - refresh its sub-item list. + @see DragAndDropContainer::startDragging + */ + virtual const String getDragSourceDescription (const SparseSet& currentlySelectedRows); +}; - When this is called with isNowOpen set to false, the subclass might want - to use clearSubItems() to save on space, or it might choose to leave them, - depending on the nature of the tree. +/** + A table of cells, using a TableHeaderComponent as its header. - You could also use this callback as a trigger to start a background process - which asynchronously creates sub-items and adds them, if that's more - appropriate for the task in hand. + This component makes it easy to create a table by providing a TableListBoxModel as + the data source. - @see mightContainSubItems - */ - virtual void itemOpennessChanged (bool isNowOpen); + @see TableListBoxModel, TableHeaderComponent +*/ +class JUCE_API TableListBox : public ListBox, + private ListBoxModel, + private TableHeaderListener +{ +public: - /** Must return the width required by this item. + /** Creates a TableListBox. - If your item needs to have a particular width in pixels, return that value; if - you'd rather have it just fill whatever space is available in the treeview, - return -1. + The model pointer passed-in can be null, in which case you can set it later + with setModel(). + */ + TableListBox (const String& componentName, + TableListBoxModel* const model); - If all your items return -1, no horizontal scrollbar will be shown, but if any - items have fixed widths and extend beyond the width of the treeview, a - scrollbar will appear. + /** Destructor. */ + ~TableListBox(); - Each item can be a different width, but if they change width, you should call - treeHasChanged() to update the tree. + /** Changes the TableListBoxModel that is being used for this table. */ - virtual int getItemWidth() const { return -1; } + void setModel (TableListBoxModel* const newModel); - /** Must return the height required by this item. + /** Returns the model currently in use. */ + TableListBoxModel* getModel() const throw() { return model; } - This is the height in pixels that the item will take up. Items in the tree - can be different heights, but if they change height, you should call - treeHasChanged() to update the tree. - */ - virtual int getItemHeight() const { return 20; } + /** Returns the header component being used in this table. */ + TableHeaderComponent* getHeader() const throw() { return header; } - /** You can override this method to return false if you don't want to allow the - user to select this item. + /** Changes the height of the table header component. + @see getHeaderHeight */ - virtual bool canBeSelected() const { return true; } - - /** Creates a component that will be used to represent this item. + void setHeaderHeight (const int newHeight); - You don't have to implement this method - if it returns 0 then no component - will be used for the item, and you can just draw it using the paintItem() - callback. But if you do return a component, it will be positioned in the - treeview so that it can be used to represent this item. + /** Returns the height of the table header. + @see setHeaderHeight + */ + int getHeaderHeight() const throw(); - The component returned will be managed by the treeview, so always return - a new component, and don't keep a reference to it, as the treeview will - delete it later when it goes off the screen or is no longer needed. Also - bear in mind that if the component keeps a reference to the item that - created it, that item could be deleted before the component. Its position - and size will be completely managed by the tree, so don't attempt to move it - around. + /** Resizes a column to fit its contents. - Something you may want to do with your component is to give it a pointer to - the TreeView that created it. This is perfectly safe, and there's no danger - of it becoming a dangling pointer because the TreeView will always delete - the component before it is itself deleted. + This uses TableListBoxModel::getColumnAutoSizeWidth() to find the best width, + and applies that to the column. - As long as you stick to these rules you can return whatever kind of - component you like. It's most useful if you're doing things like drag-and-drop - of items, or want to use a Label component to edit item names, etc. + @see autoSizeAllColumns, TableHeaderComponent::setColumnWidth */ - virtual Component* createItemComponent() { return 0; } - - /** Draws the item's contents. + void autoSizeColumn (const int columnId); - You can choose to either implement this method and draw each item, or you - can use createItemComponent() to create a component that will represent the - item. + /** Calls autoSizeColumn() for all columns in the table. */ + void autoSizeAllColumns(); - If all you need in your tree is to be able to draw the items and detect when - the user selects or double-clicks one of them, it's probably enough to - use paintItem(), itemClicked() and itemDoubleClicked(). If you need more - complicated interactions, you may need to use createItemComponent() instead. + /** Enables or disables the auto size options on the popup menu. - @param g the graphics context to draw into - @param width the width of the area available for drawing - @param height the height of the area available for drawing + By default, these are enabled. */ - virtual void paintItem (Graphics& g, int width, int height); - - /** Draws the item's open/close button. + void setAutoSizeMenuOptionShown (const bool shouldBeShown); - If you don't implement this method, the default behaviour is to - call LookAndFeel::drawTreeviewPlusMinusBox(), but you can override - it for custom effects. + /** True if the auto-size options should be shown on the menu. + @see setAutoSizeMenuOptionsShown */ - virtual void paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver); - - /** Called when the user clicks on this item. + bool isAutoSizeMenuOptionShown() const throw(); - If you're using createItemComponent() to create a custom component for the - item, the mouse-clicks might not make it through to the treeview, but this - is how you find out about clicks when just drawing each item individually. + /** Returns the position of one of the cells in the table. - The associated mouse-event details are passed in, so you can find out about - which button, where it was, etc. + If relativeToComponentTopLeft is true, the co-ordinates are relative to + the table component's top-left. The row number isn't checked to see if it's + in-range, but the column ID must exist or this will return an empty rectangle. - @see itemDoubleClicked + If relativeToComponentTopLeft is false, the co-ords are relative to the + top-left of the table's top-left cell. */ - virtual void itemClicked (const MouseEvent& e); - - /** Called when the user double-clicks on this item. - - If you're using createItemComponent() to create a custom component for the - item, the mouse-clicks might not make it through to the treeview, but this - is how you find out about clicks when just drawing each item individually. - - The associated mouse-event details are passed in, so you can find out about - which button, where it was, etc. + const Rectangle getCellPosition (const int columnId, + const int rowNumber, + const bool relativeToComponentTopLeft) const; - If not overridden, the base class method here will open or close the item as - if the 'plus' button had been clicked. + /** Scrolls horizontally if necessary to make sure that a particular column is visible. - @see itemClicked + @see ListBox::scrollToEnsureRowIsOnscreen */ - virtual void itemDoubleClicked (const MouseEvent& e); + void scrollToEnsureColumnIsOnscreen (const int columnId); - /** Called when the item is selected or deselected. + /** @internal */ + int getNumRows(); + /** @internal */ + void paintListBoxItem (int, Graphics&, int, int, bool); + /** @internal */ + Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate); + /** @internal */ + void selectedRowsChanged (int lastRowSelected); + /** @internal */ + void deleteKeyPressed (int currentSelectedRow); + /** @internal */ + void returnKeyPressed (int currentSelectedRow); + /** @internal */ + void backgroundClicked(); + /** @internal */ + void listWasScrolled(); + /** @internal */ + void tableColumnsChanged (TableHeaderComponent*); + /** @internal */ + void tableColumnsResized (TableHeaderComponent*); + /** @internal */ + void tableSortOrderChanged (TableHeaderComponent*); + /** @internal */ + void tableColumnDraggingChanged (TableHeaderComponent*, int); + /** @internal */ + void resized(); - Use this if you want to do something special when the item's selectedness - changes. By default it'll get repainted when this happens. - */ - virtual void itemSelectionChanged (bool isNowSelected); + juce_UseDebuggingNewOperator - /** The item can return a tool tip string here if it wants to. - @see TooltipClient - */ - virtual const String getTooltip(); +private: + TableHeaderComponent* header; + TableListBoxModel* model; + int columnIdNowBeingDragged; + bool autoSizeOptionsShown; - /** To allow items from your treeview to be dragged-and-dropped, implement this method. + void updateColumnComponents() const; - If this returns a non-empty name then when the user drags an item, the treeview will - try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger - a drag-and-drop operation, using this string as the source description, with the treeview - itself as the source component. + TableListBox (const TableListBox&); + const TableListBox& operator= (const TableListBox&); +}; - If you need more complex drag-and-drop behaviour, you can use custom components for - the items, and use those to trigger the drag. +#endif // __JUCE_TABLELISTBOX_JUCEHEADER__ +/********* End of inlined file: juce_TableListBox.h *********/ - To accept drag-and-drop in your tree, see isInterestedInDragSource(), - isInterestedInFileDrag(), etc. +#endif +#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ - @see DragAndDropContainer::startDragging - */ - virtual const String getDragSourceDescription(); +#endif +#ifndef __JUCE_TOOLBAR_JUCEHEADER__ - /** If you want your item to be able to have files drag-and-dropped onto it, implement this - method and return true. +#endif +#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ - If you return true and allow some files to be dropped, you'll also need to implement the - filesDropped() method to do something with them. +#endif +#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ - Note that this will be called often, so make your implementation very quick! There's - certainly no time to try opening the files and having a think about what's inside them! +/********* Start of inlined file: juce_ToolbarItemFactory.h *********/ +#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ +#define __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ - For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource(). - @see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource - */ - virtual bool isInterestedInFileDrag (const StringArray& files); +/** + A factory object which can create ToolbarItemComponent objects. - /** When files are dropped into this item, this callback is invoked. + A subclass of ToolbarItemFactory publishes a set of types of toolbar item + that it can create. - For this to work, you'll need to have also implemented isInterestedInFileDrag(). - The insertIndex value indicates where in the list of sub-items the files were dropped. - @see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag - */ - virtual void filesDropped (const StringArray& files, int insertIndex); + Each type of item is identified by a unique ID, and multiple instances of an + item type can exist at once (even on the same toolbar, e.g. spacers or separator + bars). - /** If you want your item to act as a DragAndDropTarget, implement this method and return true. + @see Toolbar, ToolbarItemComponent, ToolbarButton +*/ +class JUCE_API ToolbarItemFactory +{ +public: - If you implement this method, you'll also need to implement itemDropped() in order to handle - the items when they are dropped. - To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag(). - @see DragAndDropTarget::isInterestedInDragSource, itemDropped - */ - virtual bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent); + ToolbarItemFactory(); - /** When a things are dropped into this item, this callback is invoked. + /** Destructor. */ + virtual ~ToolbarItemFactory(); - For this to work, you need to have also implemented isInterestedInDragSource(). - The insertIndex value indicates where in the list of sub-items the new items should be placed. - @see isInterestedInDragSource, DragAndDropTarget::itemDropped + /** A set of reserved item ID values, used for the built-in item types. */ - virtual void itemDropped (const String& sourceDescription, Component* sourceComponent, int insertIndex); + enum SpecialItemIds + { + separatorBarId = -1, /**< The item ID for a vertical (or horizontal) separator bar that + can be placed between sets of items to break them into groups. */ + spacerId = -2, /**< The item ID for a fixed-width space that can be placed between + items.*/ + flexibleSpacerId = -3 /**< The item ID for a gap that pushes outwards against the things on + either side of it, filling any available space. */ + }; - /** Sets a flag to indicate that the item wants to be allowed - to draw all the way across to the left edge of the treeview. + /** Must return a list of the IDs for all the item types that this factory can create. - By default this is false, which means that when the paintItem() - method is called, its graphics context is clipped to only allow - drawing within the item's rectangle. If this flag is set to true, - then the graphics context isn't clipped on its left side, so it - can draw all the way across to the left margin. Note that the - context will still have its origin in the same place though, so - the coordinates of anything to its left will be negative. It's - mostly useful if you want to draw a wider bar behind the - highlighted item. - */ - void setDrawsInLeftMargin (bool canDrawInLeftMargin) throw(); + The ids should be added to the array that is passed-in. - /** Saves the current state of open/closed nodes so it can be restored later. + An item ID can be any integer you choose, except for 0, which is considered a null ID, + and the predefined IDs in the SpecialItemIds enum. - This takes a snapshot of which sub-nodes have been explicitly opened or closed, - and records it as XML. To identify node objects it uses the - TreeViewItem::getUniqueName() method to create named paths. This - means that the same state of open/closed nodes can be restored to a - completely different instance of the tree, as long as it contains nodes - whose unique names are the same. + You should also add the built-in types (separatorBarId, spacerId and flexibleSpacerId) + to this list if you want your toolbar to be able to contain those items. - You'd normally want to use TreeView::getOpennessState() rather than call it - for a specific item, but this can be handy if you need to briefly save the state - for a section of the tree. + The list returned here is used by the ToolbarItemPalette class to obtain its list + of available items, and their order on the palette will reflect the order in which + they appear on this list. - The caller is responsible for deleting the object that is returned. - @see TreeView::getOpennessState, restoreOpennessState + @see ToolbarItemPalette */ - XmlElement* getOpennessState() const throw(); - - /** Restores the openness of this item and all its sub-items from a saved state. + virtual void getAllToolbarItemIds (Array & ids) = 0; - See TreeView::restoreOpennessState for more details. + /** Must return the set of items that should be added to a toolbar as its default set. - You'd normally want to use TreeView::restoreOpennessState() rather than call it - for a specific item, but this can be handy if you need to briefly save the state - for a section of the tree. + This method is used by Toolbar::addDefaultItems() to determine which items to + create. - @see TreeView::restoreOpennessState, getOpennessState + The items that your method adds to the array that is passed-in will be added to the + toolbar in the same order. Items can appear in the list more than once. */ - void restoreOpennessState (const XmlElement& xml) throw(); - - /** Returns the index of this item in its parent's sub-items. */ - int getIndexInParent() const throw(); + virtual void getDefaultItemSet (Array & ids) = 0; - /** Returns true if this item is the last of its parent's sub-itens. */ - bool isLastOfSiblings() const throw(); + /** Must create an instance of one of the items that the factory lists in its + getAllToolbarItemIds() method. - /** Creates a string that can be used to uniquely retrieve this item in the tree. + The itemId parameter can be any of the values listed by your getAllToolbarItemIds() + method, except for the built-in item types from the SpecialItemIds enum, which + are created internally by the toolbar code. - The string that is returned can be passed to TreeView::findItemFromIdentifierString(). - The string takes the form of a path, constructed from the getUniqueName() of this - item and all its parents, so these must all be correctly implemented for it to work. - @see TreeView::findItemFromIdentifierString, getUniqueName + Try not to keep a pointer to the object that is returned, as it will be deleted + automatically by the toolbar, and remember that multiple instances of the same + item type are likely to exist at the same time. */ - const String getItemIdentifierString() const; - - juce_UseDebuggingNewOperator - -private: - TreeView* ownerView; - TreeViewItem* parentItem; - OwnedArray subItems; - int y, itemHeight, totalHeight, itemWidth, totalWidth; - int uid; - bool selected : 1; - bool redrawNeeded : 1; - bool drawLinesInside : 1; - bool drawsInLeftMargin : 1; - unsigned int openness : 2; + virtual ToolbarItemComponent* createItem (const int itemId) = 0; +}; - friend class TreeView; - friend class TreeViewContentComponent; +#endif // __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ +/********* End of inlined file: juce_ToolbarItemFactory.h *********/ - void updatePositions (int newY); - int getIndentX() const throw(); - void setOwnerView (TreeView* const newOwner) throw(); - void paintRecursively (Graphics& g, int width); - TreeViewItem* getTopLevelItem() throw(); - TreeViewItem* findItemRecursively (int y) throw(); - TreeViewItem* getDeepestOpenParentItem() throw(); - int getNumRows() const throw(); - TreeViewItem* getItemOnRow (int index) throw(); - void deselectAllRecursively(); - int countSelectedItemsRecursively() const throw(); - TreeViewItem* getSelectedItemWithIndex (int index) throw(); - TreeViewItem* getNextVisibleItem (const bool recurse) const throw(); - TreeViewItem* findItemFromIdentifierString (const String& identifierString); +#endif +#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ - TreeViewItem (const TreeViewItem&); - const TreeViewItem& operator= (const TreeViewItem&); -}; +/********* Start of inlined file: juce_ToolbarItemPalette.h *********/ +#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ +#define __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ /** - A tree-view component. + A component containing a list of toolbar items, which the user can drag onto + a toolbar to add them. - Use one of these to hold and display a structure of TreeViewItem objects. + You can use this class directly, but it's a lot easier to call Toolbar::showCustomisationDialog(), + which automatically shows one of these in a dialog box with lots of extra controls. + @see Toolbar */ -class JUCE_API TreeView : public Component, - public SettableTooltipClient, - public FileDragAndDropTarget, - public DragAndDropTarget, - private AsyncUpdater +class JUCE_API ToolbarItemPalette : public Component, + public DragAndDropContainer { public: - /** Creates an empty treeview. + /** Creates a palette of items for a given factory, with the aim of adding them + to the specified toolbar. - Once you've got a treeview component, you'll need to give it something to - display, using the setRootItem() method. + The ToolbarItemFactory::getAllToolbarItemIds() method is used to create the + set of items that are shown in this palette. + + The toolbar and factory must not be deleted while this object exists. */ - TreeView (const String& componentName = String::empty); + ToolbarItemPalette (ToolbarItemFactory& factory, + Toolbar* const toolbar); /** Destructor. */ - ~TreeView(); + ~ToolbarItemPalette(); - /** Sets the item that is displayed in the treeview. + /** @internal */ + void resized(); - A tree has a single root item which contains as many sub-items as it needs. If - you want the tree to contain a number of root items, you should still use a single - root item above these, but hide it using setRootItemVisible(). + juce_UseDebuggingNewOperator - You can pass in 0 to this method to clear the tree and remove its current root item. +private: + ToolbarItemFactory& factory; + Toolbar* toolbar; + Viewport* viewport; - The object passed in will not be deleted by the treeview, it's up to the caller - to delete it when no longer needed. BUT make absolutely sure that you don't delete - this item until you've removed it from the tree, either by calling setRootItem (0), - or by deleting the tree first. You can also use deleteRootItem() as a quick way - to delete it. - */ - void setRootItem (TreeViewItem* const newRootItem); + friend class Toolbar; + void replaceComponent (ToolbarItemComponent* const comp); - /** Returns the tree's root item. + ToolbarItemPalette (const ToolbarItemPalette&); + const ToolbarItemPalette& operator= (const ToolbarItemPalette&); +}; - This will be the last object passed to setRootItem(), or 0 if none has been set. - */ - TreeViewItem* getRootItem() const throw() { return rootItem; } +#endif // __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ +/********* End of inlined file: juce_ToolbarItemPalette.h *********/ - /** This will remove and delete the current root item. +#endif +#ifndef __JUCE_TREEVIEW_JUCEHEADER__ - It's a convenient way of deleting the item and calling setRootItem (0). - */ - void deleteRootItem(); +/********* Start of inlined file: juce_TreeView.h *********/ +#ifndef __JUCE_TREEVIEW_JUCEHEADER__ +#define __JUCE_TREEVIEW_JUCEHEADER__ - /** Changes whether the tree's root item is shown or not. +/********* Start of inlined file: juce_FileDragAndDropTarget.h *********/ +#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ +#define __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ - If the root item is hidden, only its sub-items will be shown in the treeview - this - lets you make the tree look as if it's got many root items. If it's hidden, this call - will also make sure the root item is open (otherwise the treeview would look empty). - */ - void setRootItemVisible (const bool shouldBeVisible); +/** + Components derived from this class can have files dropped onto them by an external application. - /** Returns true if the root item is visible. + @see DragAndDropContainer +*/ +class JUCE_API FileDragAndDropTarget +{ +public: + /** Destructor. */ + virtual ~FileDragAndDropTarget() {} - @see setRootItemVisible + /** Callback to check whether this target is interested in the set of files being offered. + + Note that this will be called repeatedly when the user is dragging the mouse around over your + component, so don't do anything time-consuming in here, like opening the files to have a look + inside them! + + @param files the set of (absolute) pathnames of the files that the user is dragging + @returns true if this component wants to receive the other callbacks regarging this + type of object; if it returns false, no other callbacks will be made. */ - bool isRootItemVisible() const throw() { return rootItemVisible; } + virtual bool isInterestedInFileDrag (const StringArray& files) = 0; - /** Sets whether items are open or closed by default. + /** Callback to indicate that some files are being dragged over this component. - Normally, items are closed until the user opens them, but you can use this - to make them default to being open until explicitly closed. + This gets called when the user moves the mouse into this component while dragging. - @see areItemsOpenByDefault + Use this callback as a trigger to make your component repaint itself to give the + user feedback about whether the files can be dropped here or not. + + @param files the set of (absolute) pathnames of the files that the user is dragging + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component */ - void setDefaultOpenness (const bool isOpenByDefault); + virtual void fileDragEnter (const StringArray& files, int x, int y); - /** Returns true if the tree's items default to being open. + /** Callback to indicate that the user is dragging some files over this component. - @see setDefaultOpenness + This gets called when the user moves the mouse over this component while dragging. + Normally overriding itemDragEnter() and itemDragExit() are enough, but + this lets you know what happens in-between. + + @param files the set of (absolute) pathnames of the files that the user is dragging + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component */ - bool areItemsOpenByDefault() const throw() { return defaultOpenness; } + virtual void fileDragMove (const StringArray& files, int x, int y); - /** This sets a flag to indicate that the tree can be used for multi-selection. + /** Callback to indicate that the mouse has moved away from this component. - You can always select multiple items internally by calling the - TreeViewItem::setSelected() method, but this flag indicates whether the user - is allowed to multi-select by clicking on the tree. + This gets called when the user moves the mouse out of this component while dragging + the files. - By default it is disabled. + If you've used fileDragEnter() to repaint your component and give feedback, use this + as a signal to repaint it in its normal state. - @see isMultiSelectEnabled + @param files the set of (absolute) pathnames of the files that the user is dragging */ - void setMultiSelectEnabled (const bool canMultiSelect); + virtual void fileDragExit (const StringArray& files); - /** Returns whether multi-select has been enabled for the tree. + /** Callback to indicate that the user has dropped the files onto this component. - @see setMultiSelectEnabled - */ - bool isMultiSelectEnabled() const throw() { return multiSelectEnabled; } + When the user drops the files, this get called, and you can use the files in whatever + way is appropriate. - /** Sets a flag to indicate whether to hide the open/close buttons. + Note that after this is called, the fileDragExit method may not be called, so you should + clean up in here if there's anything you need to do when the drag finishes. - @see areOpenCloseButtonsVisible + @param files the set of (absolute) pathnames of the files that the user is dragging + @param x the mouse x position, relative to this component + @param y the mouse y position, relative to this component */ - void setOpenCloseButtonsVisible (const bool shouldBeVisible); + virtual void filesDropped (const StringArray& files, int x, int y) = 0; +}; - /** Returns whether open/close buttons are shown. +#endif // __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ +/********* End of inlined file: juce_FileDragAndDropTarget.h *********/ - @see setOpenCloseButtonsVisible - */ - bool areOpenCloseButtonsVisible() const throw() { return openCloseButtonsVisible; } +class TreeView; - /** Deselects any items that are currently selected. */ - void clearSelectedItems(); +/** + An item in a treeview. - /** Returns the number of items that are currently selected. + A TreeViewItem can either be a leaf-node in the tree, or it can contain its + own sub-items. - @see getSelectedItem, clearSelectedItems - */ - int getNumSelectedItems() const throw(); + To implement an item that contains sub-items, override the itemOpennessChanged() + method so that when it is opened, it adds the new sub-items to itself using the + addSubItem method. Depending on the nature of the item it might choose to only + do this the first time it's opened, or it might want to refresh itself each time. + It also has the option of deleting its sub-items when it is closed, or leaving them + in place. +*/ +class JUCE_API TreeViewItem +{ +public: - /** Returns one of the selected items in the tree. + /** Constructor. */ + TreeViewItem(); - @param index the index, 0 to (getNumSelectedItems() - 1) - */ - TreeViewItem* getSelectedItem (const int index) const throw(); + /** Destructor. */ + virtual ~TreeViewItem(); - /** Returns the number of rows the tree is using. + /** Returns the number of sub-items that have been added to this item. - This will depend on which items are open. + Note that this doesn't mean much if the node isn't open. - @see TreeViewItem::getRowNumberInTree() + @see getSubItem, mightContainSubItems, addSubItem */ - int getNumRowsInTree() const; - - /** Returns the item on a particular row of the tree. + int getNumSubItems() const throw(); - If the index is out of range, this will return 0. + /** Returns one of the item's sub-items. - @see getNumRowsInTree, TreeViewItem::getRowNumberInTree() - */ - TreeViewItem* getItemOnRow (int index) const; + Remember that the object returned might get deleted at any time when its parent + item is closed or refreshed, depending on the nature of the items you're using. - /** Returns the item that contains a given y position. - The y is relative to the top of the TreeView component. + @see getNumSubItems */ - TreeViewItem* getItemAt (int yPosition) const throw(); + TreeViewItem* getSubItem (const int index) const throw(); - /** Tries to scroll the tree so that this item is on-screen somewhere. */ - void scrollToKeepItemVisible (TreeViewItem* item); + /** Removes any sub-items. */ + void clearSubItems(); - /** Returns the treeview's Viewport object. */ - Viewport* getViewport() const throw() { return viewport; } + /** Adds a sub-item. - /** Returns the number of pixels by which each nested level of the tree is indented. - @see setIndentSize + @param newItem the object to add to the item's sub-item list. Once added, these can be + found using getSubItem(). When the items are later removed with + removeSubItem() (or when this item is deleted), they will be deleted. + @param insertPosition the index which the new item should have when it's added. If this + value is less than 0, the item will be added to the end of the list. */ - int getIndentSize() const throw() { return indentSize; } + void addSubItem (TreeViewItem* const newItem, + const int insertPosition = -1); - /** Changes the distance by which each nested level of the tree is indented. - @see getIndentSize - */ - void setIndentSize (const int newIndentSize); + /** Removes one of the sub-items. - /** Searches the tree for an item with the specified identifier. - The identifer string must have been created by calling TreeViewItem::getItemIdentifierString(). - If no such item exists, this will return false. If the item is found, all of its items - will be automatically opened. + @param index the item to remove + @param deleteItem if true, the item that is removed will also be deleted. */ - TreeViewItem* findItemFromIdentifierString (const String& identifierString) const; - - /** Saves the current state of open/closed nodes so it can be restored later. + void removeSubItem (const int index, + const bool deleteItem = true); - This takes a snapshot of which nodes have been explicitly opened or closed, - and records it as XML. To identify node objects it uses the - TreeViewItem::getUniqueName() method to create named paths. This - means that the same state of open/closed nodes can be restored to a - completely different instance of the tree, as long as it contains nodes - whose unique names are the same. + /** Returns the TreeView to which this item belongs. */ + TreeView* getOwnerView() const throw() { return ownerView; } - The caller is responsible for deleting the object that is returned. + /** Returns the item within which this item is contained. */ + TreeViewItem* getParentItem() const throw() { return parentItem; } - @param alsoIncludeScrollPosition if this is true, the state will also - include information about where the - tree has been scrolled to vertically, - so this can also be restored - @see restoreOpennessState - */ - XmlElement* getOpennessState (const bool alsoIncludeScrollPosition) const; + /** True if this item is currently open in the treeview. */ + bool isOpen() const throw(); - /** Restores a previously saved arrangement of open/closed nodes. + /** Opens or closes the item. - This will try to restore a snapshot of the tree's state that was created by - the getOpennessState() method. If any of the nodes named in the original - XML aren't present in this tree, they will be ignored. + When opened or closed, the item's itemOpennessChanged() method will be called, + and a subclass should use this callback to create and add any sub-items that + it needs to. - @see getOpennessState + @see itemOpennessChanged, mightContainSubItems */ - void restoreOpennessState (const XmlElement& newState); - - /** A set of colour IDs to use to change the colour of various aspects of the treeview. + void setOpen (const bool shouldBeOpen); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** True if this item is currently selected. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + Use this when painting the node, to decide whether to draw it as selected or not. */ - enum ColourIds - { - backgroundColourId = 0x1000500, /**< A background colour to fill the component with. */ - linesColourId = 0x1000501, /**< The colour to draw the lines with.*/ - dragAndDropIndicatorColourId = 0x1000502 /**< The colour to use for the drag-and-drop target position indicator. */ - }; - - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void colourChanged(); - /** @internal */ - void enablementChanged(); - /** @internal */ - bool isInterestedInFileDrag (const StringArray& files); - /** @internal */ - void fileDragEnter (const StringArray& files, int x, int y); - /** @internal */ - void fileDragMove (const StringArray& files, int x, int y); - /** @internal */ - void fileDragExit (const StringArray& files); - /** @internal */ - void filesDropped (const StringArray& files, int x, int y); - /** @internal */ - bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent); - /** @internal */ - void itemDragEnter (const String& sourceDescription, Component* sourceComponent, int x, int y); - /** @internal */ - void itemDragMove (const String& sourceDescription, Component* sourceComponent, int x, int y); - /** @internal */ - void itemDragExit (const String& sourceDescription, Component* sourceComponent); - /** @internal */ - void itemDropped (const String& sourceDescription, Component* sourceComponent, int x, int y); - - juce_UseDebuggingNewOperator + bool isSelected() const throw(); -private: - friend class TreeViewItem; - friend class TreeViewContentComponent; - Viewport* viewport; - CriticalSection nodeAlterationLock; - TreeViewItem* rootItem; - Component* dragInsertPointHighlight; - Component* dragTargetGroupHighlight; - int indentSize; - bool defaultOpenness : 1; - bool needsRecalculating : 1; - bool rootItemVisible : 1; - bool multiSelectEnabled : 1; - bool openCloseButtonsVisible : 1; + /** Selects or deselects the item. - void itemsChanged() throw(); - void handleAsyncUpdate(); - void moveSelectedRow (int delta); - void updateButtonUnderMouse (const MouseEvent& e); - void showDragHighlight (TreeViewItem* item, int insertIndex, int x, int y) throw(); - void hideDragHighlight() throw(); - void handleDrag (const StringArray& files, const String& sourceDescription, Component* sourceComponent, int x, int y); - void handleDrop (const StringArray& files, const String& sourceDescription, Component* sourceComponent, int x, int y); - TreeViewItem* getInsertPosition (int& x, int& y, int& insertIndex, - const StringArray& files, const String& sourceDescription, - Component* sourceComponent) const throw(); + This will cause a callback to itemSelectionChanged() + */ + void setSelected (const bool shouldBeSelected, + const bool deselectOtherItemsFirst); - TreeView (const TreeView&); - const TreeView& operator= (const TreeView&); -}; + /** Returns the rectangle that this item occupies. -#endif // __JUCE_TREEVIEW_JUCEHEADER__ -/********* End of inlined file: juce_TreeView.h *********/ + If relativeToTreeViewTopLeft is true, the co-ordinates are relative to the + top-left of the TreeView comp, so this will depend on the scroll-position of + the tree. If false, it is relative to the top-left of the topmost item in the + tree (so this would be unaffected by scrolling the view). + */ + const Rectangle getItemPosition (const bool relativeToTreeViewTopLeft) const throw(); -/** - A component to allow editing of the keymaps stored by a KeyPressMappingSet - object. + /** Sends a signal to the treeview to make it refresh itself. - @see KeyPressMappingSet -*/ -class JUCE_API KeyMappingEditorComponent : public Component, - public TreeViewItem, - public ChangeListener, - private ButtonListener -{ -public: + Call this if your items have changed and you want the tree to update to reflect + this. + */ + void treeHasChanged() const throw(); - /** Creates a KeyMappingEditorComponent. + /** Sends a repaint message to redraw just this item. - @param mappingSet this is the set of mappings to display and - edit. Make sure the mappings object is not - deleted before this component! - @param showResetToDefaultButton if true, then at the bottom of the - list, the component will include a 'reset to - defaults' button. + Note that you should only call this if you want to repaint a superficial change. If + you're altering the tree's nodes, you should instead call treeHasChanged(). */ - KeyMappingEditorComponent (KeyPressMappingSet* const mappingSet, - const bool showResetToDefaultButton); - - /** Destructor. */ - virtual ~KeyMappingEditorComponent(); + void repaintItem() const; - /** Sets up the colours to use for parts of the component. + /** Returns the row number of this item in the tree. - @param mainBackground colour to use for most of the background - @param textColour colour to use for the text - */ - void setColours (const Colour& mainBackground, - const Colour& textColour); + The row number of an item will change according to which items are open. - /** Returns the KeyPressMappingSet that this component is acting upon. + @see TreeView::getNumRowsInTree(), TreeView::getItemOnRow() */ - KeyPressMappingSet* getMappings() const throw() { return mappings; } + int getRowNumberInTree() const throw(); - /** Can be overridden if some commands need to be excluded from the list. + /** Returns true if all the item's parent nodes are open. - By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor() - method to decide what to return, but you can override it to handle special cases. + This is useful to check whether the item might actually be visible or not. */ - virtual bool shouldCommandBeIncluded (const CommandID commandID); + bool areAllParentsOpen() const throw(); - /** Can be overridden to indicate that some commands are shown as read-only. + /** Changes whether lines are drawn to connect any sub-items to this item. - By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor() - method to decide what to return, but you can override it to handle special cases. + By default, line-drawing is turned on. */ - virtual bool isCommandReadOnly (const CommandID commandID); + void setLinesDrawnForSubItems (const bool shouldDrawLines) throw(); - /** This can be overridden to let you change the format of the string used - to describe a keypress. + /** Tells the tree whether this item can potentially be opened. - This is handy if you're using non-standard KeyPress objects, e.g. for custom - keys that are triggered by something else externally. If you override the - method, be sure to let the base class's method handle keys you're not - interested in. + If your item could contain sub-items, this should return true; if it returns + false then the tree will not try to open the item. This determines whether or + not the item will be drawn with a 'plus' button next to it. */ - virtual const String getDescriptionForKeyPress (const KeyPress& key); - - /** A set of colour IDs to use to change the colour of various aspects of the editor. + virtual bool mightContainSubItems() = 0; - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** Returns a string to uniquely identify this item. - To change the colours of the menu that pops up + If you're planning on using the TreeView::getOpennessState() method, then + these strings will be used to identify which nodes are open. The string + should be unique amongst the item's sibling items, but it's ok for there + to be duplicates at other levels of the tree. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + If you're not going to store the state, then it's ok not to bother implementing + this method. */ - enum ColourIds - { - backgroundColourId = 0x100ad00, /**< The background colour to fill the editor background. */ - textColourId = 0x100ad01, /**< The colour for the text. */ - }; - - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - void resized(); - /** @internal */ - void changeListenerCallback (void*); - /** @internal */ - bool mightContainSubItems(); - /** @internal */ - const String getUniqueName() const; - /** @internal */ - void buttonClicked (Button* button); + virtual const String getUniqueName() const; - juce_UseDebuggingNewOperator + /** Called when an item is opened or closed. -private: + When setOpen() is called and the item has specified that it might + have sub-items with the mightContainSubItems() method, this method + is called to let the item create or manage its sub-items. - KeyPressMappingSet* mappings; - TreeView* tree; - friend class KeyMappingTreeViewItem; - friend class KeyCategoryTreeViewItem; - friend class KeyMappingItemComponent; - friend class KeyMappingChangeButton; - TextButton* resetButton; + So when this is called with isNowOpen set to true (i.e. when the item is being + opened), a subclass might choose to use clearSubItems() and addSubItem() to + refresh its sub-item list. - void assignNewKey (const CommandID commandID, int index); + When this is called with isNowOpen set to false, the subclass might want + to use clearSubItems() to save on space, or it might choose to leave them, + depending on the nature of the tree. - KeyMappingEditorComponent (const KeyMappingEditorComponent&); - const KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); -}; + You could also use this callback as a trigger to start a background process + which asynchronously creates sub-items and adds them, if that's more + appropriate for the task in hand. -#endif // __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_KeyMappingEditorComponent.h *********/ + @see mightContainSubItems + */ + virtual void itemOpennessChanged (bool isNowOpen); -#endif -#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ + /** Must return the width required by this item. -/********* Start of inlined file: juce_CodeEditorComponent.h *********/ -#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ -#define __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ + If your item needs to have a particular width in pixels, return that value; if + you'd rather have it just fill whatever space is available in the treeview, + return -1. -/********* Start of inlined file: juce_CodeDocument.h *********/ -#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ -#define __JUCE_CODEDOCUMENT_JUCEHEADER__ + If all your items return -1, no horizontal scrollbar will be shown, but if any + items have fixed widths and extend beyond the width of the treeview, a + scrollbar will appear. -class CodeDocumentLine; + Each item can be a different width, but if they change width, you should call + treeHasChanged() to update the tree. + */ + virtual int getItemWidth() const { return -1; } -/** - A class for storing and manipulating a source code file. + /** Must return the height required by this item. - When using a CodeEditorComponent, it takes one of these as its source object. + This is the height in pixels that the item will take up. Items in the tree + can be different heights, but if they change height, you should call + treeHasChanged() to update the tree. + */ + virtual int getItemHeight() const { return 20; } - The CodeDocument stores its content as an array of lines, which makes it - quick to insert and delete. - - @see CodeEditorComponent -*/ -class JUCE_API CodeDocument -{ -public: - /** Creates a new, empty document. + /** You can override this method to return false if you don't want to allow the + user to select this item. */ - CodeDocument(); - - /** Destructor. */ - ~CodeDocument(); + virtual bool canBeSelected() const { return true; } - /** A position in a code document. + /** Creates a component that will be used to represent this item. - Using this class you can find a position in a code document and quickly get its - character position, line, and index. By calling setPositionMaintained (true), the - position is automatically updated when text is inserted or deleted in the document, - so that it maintains its original place in the text. - */ - class JUCE_API Position - { - public: - /** Creates an uninitialised postion. - Don't attempt to call any methods on this until you've given it an owner document - to refer to! - */ - Position() throw(); + You don't have to implement this method - if it returns 0 then no component + will be used for the item, and you can just draw it using the paintItem() + callback. But if you do return a component, it will be positioned in the + treeview so that it can be used to represent this item. - /** Creates a position based on a line and index in a document. + The component returned will be managed by the treeview, so always return + a new component, and don't keep a reference to it, as the treeview will + delete it later when it goes off the screen or is no longer needed. Also + bear in mind that if the component keeps a reference to the item that + created it, that item could be deleted before the component. Its position + and size will be completely managed by the tree, so don't attempt to move it + around. - Note that this index is NOT the column number, it's the number of characters from the - start of the line. The "column" number isn't quite the same, because if the line - contains any tab characters, the relationship of the index to its visual column depends on - the number of spaces per tab being used! + Something you may want to do with your component is to give it a pointer to + the TreeView that created it. This is perfectly safe, and there's no danger + of it becoming a dangling pointer because the TreeView will always delete + the component before it is itself deleted. - Lines are numbered from zero, and if the line or index are beyond the bounds of the document, - they will be adjusted to keep them within its limits. - */ - Position (const CodeDocument* const ownerDocument, - const int line, const int indexInLine) throw(); + As long as you stick to these rules you can return whatever kind of + component you like. It's most useful if you're doing things like drag-and-drop + of items, or want to use a Label component to edit item names, etc. + */ + virtual Component* createItemComponent() { return 0; } - /** Creates a position based on a character index in a document. - This position is placed at the specified number of characters from the start of the - document. The line and column are auto-calculated. + /** Draws the item's contents. - If the position is beyond the range of the document, it'll be adjusted to keep it - inside. - */ - Position (const CodeDocument* const ownerDocument, - const int charactersFromStartOfDocument) throw(); + You can choose to either implement this method and draw each item, or you + can use createItemComponent() to create a component that will represent the + item. - /** Creates a copy of another position. + If all you need in your tree is to be able to draw the items and detect when + the user selects or double-clicks one of them, it's probably enough to + use paintItem(), itemClicked() and itemDoubleClicked(). If you need more + complicated interactions, you may need to use createItemComponent() instead. - This will copy the position, but the new object will not be set to maintain its position, - even if the source object was set to do so. - */ - Position (const Position& other) throw(); + @param g the graphics context to draw into + @param width the width of the area available for drawing + @param height the height of the area available for drawing + */ + virtual void paintItem (Graphics& g, int width, int height); - /** Destructor. */ - ~Position() throw(); + /** Draws the item's open/close button. - const Position& operator= (const Position& other) throw(); - bool operator== (const Position& other) const throw(); - bool operator!= (const Position& other) const throw(); + If you don't implement this method, the default behaviour is to + call LookAndFeel::drawTreeviewPlusMinusBox(), but you can override + it for custom effects. + */ + virtual void paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver); - /** Points this object at a new position within the document. + /** Called when the user clicks on this item. - If the position is beyond the range of the document, it'll be adjusted to keep it - inside. - @see getPosition, setLineAndIndex - */ - void setPosition (const int charactersFromStartOfDocument) throw(); + If you're using createItemComponent() to create a custom component for the + item, the mouse-clicks might not make it through to the treeview, but this + is how you find out about clicks when just drawing each item individually. - /** Returns the position as the number of characters from the start of the document. - @see setPosition, getLineNumber, getIndexInLine - */ - int getPosition() const throw() { return characterPos; } + The associated mouse-event details are passed in, so you can find out about + which button, where it was, etc. - /** Moves the position to a new line and index within the line. + @see itemDoubleClicked + */ + virtual void itemClicked (const MouseEvent& e); - Note that the index is NOT the column at which the position appears in an editor. - If the line contains any tab characters, the relationship of the index to its - visual position depends on the number of spaces per tab being used! + /** Called when the user double-clicks on this item. - Lines are numbered from zero, and if the line or index are beyond the bounds of the document, - they will be adjusted to keep them within its limits. - */ - void setLineAndIndex (const int newLine, const int newIndexInLine) throw(); + If you're using createItemComponent() to create a custom component for the + item, the mouse-clicks might not make it through to the treeview, but this + is how you find out about clicks when just drawing each item individually. - /** Returns the line number of this position. - The first line in the document is numbered zero, not one! - */ - int getLineNumber() const throw() { return line; } + The associated mouse-event details are passed in, so you can find out about + which button, where it was, etc. - /** Returns the number of characters from the start of the line. + If not overridden, the base class method here will open or close the item as + if the 'plus' button had been clicked. - Note that this value is NOT the column at which the position appears in an editor. - If the line contains any tab characters, the relationship of the index to its - visual position depends on the number of spaces per tab being used! - */ - int getIndexInLine() const throw() { return indexInLine; } + @see itemClicked + */ + virtual void itemDoubleClicked (const MouseEvent& e); - /** Allows the position to be automatically updated when the document changes. + /** Called when the item is selected or deselected. - If this is set to true, the positon will register with its document so that - when the document has text inserted or deleted, this position will be automatically - moved to keep it at the same position in the text. - */ - void setPositionMaintained (const bool isMaintained) throw(); + Use this if you want to do something special when the item's selectedness + changes. By default it'll get repainted when this happens. + */ + virtual void itemSelectionChanged (bool isNowSelected); - /** Moves the position forwards or backwards by the specified number of characters. - @see movedBy - */ - void moveBy (int characterDelta) throw(); + /** The item can return a tool tip string here if it wants to. + @see TooltipClient + */ + virtual const String getTooltip(); - /** Returns a position which is the same as this one, moved by the specified number of - characters. - @see moveBy - */ - const Position movedBy (const int characterDelta) const throw(); + /** To allow items from your treeview to be dragged-and-dropped, implement this method. - /** Returns a position which is the same as this one, moved up or down by the specified - number of lines. - @see movedBy - */ - const Position movedByLines (const int deltaLines) const throw(); + If this returns a non-empty name then when the user drags an item, the treeview will + try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger + a drag-and-drop operation, using this string as the source description, with the treeview + itself as the source component. - /** Returns the character in the document at this position. - @see getLineText - */ - const tchar getCharacter() const throw(); + If you need more complex drag-and-drop behaviour, you can use custom components for + the items, and use those to trigger the drag. - /** Returns the line from the document that this position is within. - @see getCharacter, getLineNumber - */ - const String getLineText() const throw(); + To accept drag-and-drop in your tree, see isInterestedInDragSource(), + isInterestedInFileDrag(), etc. - private: - CodeDocument* owner; - int characterPos, line, indexInLine; - bool positionMaintained; - }; + @see DragAndDropContainer::startDragging + */ + virtual const String getDragSourceDescription(); - /** Returns the full text of the document. */ - const String getAllContent() const throw(); + /** If you want your item to be able to have files drag-and-dropped onto it, implement this + method and return true. - /** Returns a section of the document's text. */ - const String getTextBetween (const Position& start, const Position& end) const throw(); + If you return true and allow some files to be dropped, you'll also need to implement the + filesDropped() method to do something with them. - /** Returns a line from the document. */ - const String getLine (const int lineIndex) const throw(); + Note that this will be called often, so make your implementation very quick! There's + certainly no time to try opening the files and having a think about what's inside them! - /** Returns the number of characters in the document. */ - int getNumCharacters() const throw(); + For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource(). + @see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource + */ + virtual bool isInterestedInFileDrag (const StringArray& files); - /** Returns the number of lines in the document. */ - int getNumLines() const throw() { return lines.size(); } + /** When files are dropped into this item, this callback is invoked. - /** Returns the number of characters in the longest line of the document. */ - int getMaximumLineLength() throw(); + For this to work, you'll need to have also implemented isInterestedInFileDrag(). + The insertIndex value indicates where in the list of sub-items the files were dropped. + @see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag + */ + virtual void filesDropped (const StringArray& files, int insertIndex); - /** Deletes a section of the text. + /** If you want your item to act as a DragAndDropTarget, implement this method and return true. - This operation is undoable. + If you implement this method, you'll also need to implement itemDropped() in order to handle + the items when they are dropped. + To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag(). + @see DragAndDropTarget::isInterestedInDragSource, itemDropped */ - void deleteSection (const Position& startPosition, const Position& endPosition); + virtual bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent); - /** Inserts some text into the document at a given position. + /** When a things are dropped into this item, this callback is invoked. - This operation is undoable. + For this to work, you need to have also implemented isInterestedInDragSource(). + The insertIndex value indicates where in the list of sub-items the new items should be placed. + @see isInterestedInDragSource, DragAndDropTarget::itemDropped */ - void insertText (const Position& position, const String& text); + virtual void itemDropped (const String& sourceDescription, Component* sourceComponent, int insertIndex); - /** Clears the document and replaces it with some new text. + /** Sets a flag to indicate that the item wants to be allowed + to draw all the way across to the left edge of the treeview. - This operation is undoable - if you're trying to completely reset the document, you - might want to also call clearUndoHistory() and setSavePoint() after using this method. + By default this is false, which means that when the paintItem() + method is called, its graphics context is clipped to only allow + drawing within the item's rectangle. If this flag is set to true, + then the graphics context isn't clipped on its left side, so it + can draw all the way across to the left margin. Note that the + context will still have its origin in the same place though, so + the coordinates of anything to its left will be negative. It's + mostly useful if you want to draw a wider bar behind the + highlighted item. */ - void replaceAllContent (const String& newContent); + void setDrawsInLeftMargin (bool canDrawInLeftMargin) throw(); - /** Returns the preferred new-line characters for the document. - This will be either "\n", "\r\n", or (rarely) "\r". - @see setNewLineCharacters - */ - const String getNewLineCharacters() const throw() { return newLineChars; } + /** Saves the current state of open/closed nodes so it can be restored later. - /** Sets the new-line characters that the document should use. - The string must be either "\n", "\r\n", or (rarely) "\r". - @see getNewLineCharacters - */ - void setNewLineCharacters (const String& newLine) throw(); + This takes a snapshot of which sub-nodes have been explicitly opened or closed, + and records it as XML. To identify node objects it uses the + TreeViewItem::getUniqueName() method to create named paths. This + means that the same state of open/closed nodes can be restored to a + completely different instance of the tree, as long as it contains nodes + whose unique names are the same. - /** Begins a new undo transaction. + You'd normally want to use TreeView::getOpennessState() rather than call it + for a specific item, but this can be handy if you need to briefly save the state + for a section of the tree. - The document itself will not call this internally, so relies on whatever is using the - document to periodically call this to break up the undo sequence into sensible chunks. - @see UndoManager::beginNewTransaction + The caller is responsible for deleting the object that is returned. + @see TreeView::getOpennessState, restoreOpennessState */ - void newTransaction(); + XmlElement* getOpennessState() const throw(); - /** Undo the last operation. - @see UndoManager::undo - */ - void undo(); + /** Restores the openness of this item and all its sub-items from a saved state. - /** Redo the last operation. - @see UndoManager::redo - */ - void redo(); + See TreeView::restoreOpennessState for more details. - /** Clears the undo history. - @see UndoManager::clearUndoHistory + You'd normally want to use TreeView::restoreOpennessState() rather than call it + for a specific item, but this can be handy if you need to briefly save the state + for a section of the tree. + + @see TreeView::restoreOpennessState, getOpennessState */ - void clearUndoHistory(); + void restoreOpennessState (const XmlElement& xml) throw(); - /** Returns the document's UndoManager */ - UndoManager& getUndoManager() throw() { return undoManager; } + /** Returns the index of this item in its parent's sub-items. */ + int getIndexInParent() const throw(); - /** Makes a note that the document's current state matches the one that is saved. + /** Returns true if this item is the last of its parent's sub-itens. */ + bool isLastOfSiblings() const throw(); - After this has been called, hasChangedSinceSavePoint() will return false until - the document has been altered, and then it'll start returning true. If the document is - altered, but then undone until it gets back to this state, hasChangedSinceSavePoint() - will again return false. + /** Creates a string that can be used to uniquely retrieve this item in the tree. - @see hasChangedSinceSavePoint + The string that is returned can be passed to TreeView::findItemFromIdentifierString(). + The string takes the form of a path, constructed from the getUniqueName() of this + item and all its parents, so these must all be correctly implemented for it to work. + @see TreeView::findItemFromIdentifierString, getUniqueName */ - void setSavePoint() throw(); - - /** Returns true if the state of the document differs from the state it was in when - setSavePoint() was last called. + const String getItemIdentifierString() const; - @see setSavePoint - */ - bool hasChangedSinceSavePoint() const throw(); + juce_UseDebuggingNewOperator - /** Searches for a word-break. */ - const Position findWordBreakAfter (const Position& position) const throw(); +private: + TreeView* ownerView; + TreeViewItem* parentItem; + OwnedArray subItems; + int y, itemHeight, totalHeight, itemWidth, totalWidth; + int uid; + bool selected : 1; + bool redrawNeeded : 1; + bool drawLinesInside : 1; + bool drawsInLeftMargin : 1; + unsigned int openness : 2; - /** Searches for a word-break. */ - const Position findWordBreakBefore (const Position& position) const throw(); + friend class TreeView; + friend class TreeViewContentComponent; - /** An object that receives callbacks from the CodeDocument when its text changes. - @see CodeDocument::addListener, CodeDocument::removeListener - */ - class JUCE_API Listener - { - public: - Listener() {} - virtual ~Listener() {} + void updatePositions (int newY); + int getIndentX() const throw(); + void setOwnerView (TreeView* const newOwner) throw(); + void paintRecursively (Graphics& g, int width); + TreeViewItem* getTopLevelItem() throw(); + TreeViewItem* findItemRecursively (int y) throw(); + TreeViewItem* getDeepestOpenParentItem() throw(); + int getNumRows() const throw(); + TreeViewItem* getItemOnRow (int index) throw(); + void deselectAllRecursively(); + int countSelectedItemsRecursively() const throw(); + TreeViewItem* getSelectedItemWithIndex (int index) throw(); + TreeViewItem* getNextVisibleItem (const bool recurse) const throw(); + TreeViewItem* findItemFromIdentifierString (const String& identifierString); - /** Called by a CodeDocument when it is altered. - */ - virtual void codeDocumentChanged (const Position& affectedTextStart, - const Position& affectedTextEnd) = 0; - }; + TreeViewItem (const TreeViewItem&); + const TreeViewItem& operator= (const TreeViewItem&); +}; - /** Registers a listener object to receive callbacks when the document changes. - If the listener is already registered, this method has no effect. - @see removeListener - */ - void addListener (Listener* const listener) throw(); +/** + A tree-view component. - /** Deregisters a listener. - @see addListener - */ - void removeListener (Listener* const listener) throw(); + Use one of these to hold and display a structure of TreeViewItem objects. - /** Iterates the text in a CodeDocument. +*/ +class JUCE_API TreeView : public Component, + public SettableTooltipClient, + public FileDragAndDropTarget, + public DragAndDropTarget, + private AsyncUpdater +{ +public: - This class lets you read characters from a CodeDocument. It's designed to be used - by a SyntaxAnalyser object. + /** Creates an empty treeview. - @see CodeDocument, SyntaxAnalyser + Once you've got a treeview component, you'll need to give it something to + display, using the setRootItem() method. */ - class Iterator - { - public: - Iterator (CodeDocument* const document) throw(); - Iterator (const Iterator& other); - const Iterator& operator= (const Iterator& other) throw(); - ~Iterator() throw(); + TreeView (const String& componentName = String::empty); - /** Reads the next character and returns it. - @see peekNextChar - */ - juce_wchar nextChar() throw(); + /** Destructor. */ + ~TreeView(); - /** Reads the next character without advancing the current position. */ - juce_wchar peekNextChar() const throw(); + /** Sets the item that is displayed in the treeview. - /** Advances the position by one character. */ - void skip() throw(); + A tree has a single root item which contains as many sub-items as it needs. If + you want the tree to contain a number of root items, you should still use a single + root item above these, but hide it using setRootItemVisible(). - /** Returns the position of the next character as its position within the - whole document. - */ - int getPosition() const throw() { return position; } + You can pass in 0 to this method to clear the tree and remove its current root item. - /** Skips over any whitespace characters until the next character is non-whitespace. */ - void skipWhitespace(); + The object passed in will not be deleted by the treeview, it's up to the caller + to delete it when no longer needed. BUT make absolutely sure that you don't delete + this item until you've removed it from the tree, either by calling setRootItem (0), + or by deleting the tree first. You can also use deleteRootItem() as a quick way + to delete it. + */ + void setRootItem (TreeViewItem* const newRootItem); - /** Skips forward until the next character will be the first character on the next line */ - void skipToEndOfLine(); + /** Returns the tree's root item. - /** Returns the line number of the next character. */ - int getLine() const throw() { return line; } + This will be the last object passed to setRootItem(), or 0 if none has been set. + */ + TreeViewItem* getRootItem() const throw() { return rootItem; } - /** Returns true if the iterator has reached the end of the document. */ - bool isEOF() const throw(); + /** This will remove and delete the current root item. - private: - CodeDocument* document; - int line, position; - }; + It's a convenient way of deleting the item and calling setRootItem (0). + */ + void deleteRootItem(); - juce_UseDebuggingNewOperator + /** Changes whether the tree's root item is shown or not. -private: - friend class CodeDocumentInsertAction; - friend class CodeDocumentDeleteAction; - friend class Iterator; - friend class Position; + If the root item is hidden, only its sub-items will be shown in the treeview - this + lets you make the tree look as if it's got many root items. If it's hidden, this call + will also make sure the root item is open (otherwise the treeview would look empty). + */ + void setRootItemVisible (const bool shouldBeVisible); - OwnedArray lines; - Array positionsToMaintain; - UndoManager undoManager; - int currentActionIndex, indexOfSavedState; - int maximumLineLength; - VoidArray listeners; - String newLineChars; + /** Returns true if the root item is visible. - void sendListenerChangeMessage (const int startLine, const int endLine); + @see setRootItemVisible + */ + bool isRootItemVisible() const throw() { return rootItemVisible; } - void insert (const String& text, const int insertPos, const bool undoable); - void remove (const int startPos, const int endPos, const bool undoable); + /** Sets whether items are open or closed by default. - CodeDocument (const CodeDocument&); - const CodeDocument& operator= (const CodeDocument&); -}; + Normally, items are closed until the user opens them, but you can use this + to make them default to being open until explicitly closed. -#endif // __JUCE_CODEDOCUMENT_JUCEHEADER__ -/********* End of inlined file: juce_CodeDocument.h *********/ + @see areItemsOpenByDefault + */ + void setDefaultOpenness (const bool isOpenByDefault); -/********* Start of inlined file: juce_CodeTokeniser.h *********/ -#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ -#define __JUCE_CODETOKENISER_JUCEHEADER__ + /** Returns true if the tree's items default to being open. -/** - A base class for tokenising code so that the syntax can be displayed in a - code editor. + @see setDefaultOpenness + */ + bool areItemsOpenByDefault() const throw() { return defaultOpenness; } - @see CodeDocument, CodeEditorComponent -*/ -class JUCE_API CodeTokeniser -{ -public: - CodeTokeniser() {} - virtual ~CodeTokeniser() {} + /** This sets a flag to indicate that the tree can be used for multi-selection. - /** Reads the next token from the source and returns its token type. + You can always select multiple items internally by calling the + TreeViewItem::setSelected() method, but this flag indicates whether the user + is allowed to multi-select by clicking on the tree. - This must leave the source pointing to the first character in the - next token. + By default it is disabled. + + @see isMultiSelectEnabled */ - virtual int readNextToken (CodeDocument::Iterator& source) = 0; + void setMultiSelectEnabled (const bool canMultiSelect); - /** Returns a list of the names of the token types this analyser uses. + /** Returns whether multi-select has been enabled for the tree. - The index in this list must match the token type numbers that are - returned by readNextToken(). + @see setMultiSelectEnabled */ - virtual const StringArray getTokenTypes() = 0; + bool isMultiSelectEnabled() const throw() { return multiSelectEnabled; } - /** Returns a suggested syntax highlighting colour for a specified - token type. - */ - virtual const Colour getDefaultColour (const int tokenType) = 0; + /** Sets a flag to indicate whether to hide the open/close buttons. - juce_UseDebuggingNewOperator -}; + @see areOpenCloseButtonsVisible + */ + void setOpenCloseButtonsVisible (const bool shouldBeVisible); -#endif // __JUCE_CODETOKENISER_JUCEHEADER__ -/********* End of inlined file: juce_CodeTokeniser.h *********/ + /** Returns whether open/close buttons are shown. -class CodeEditorLine; + @see setOpenCloseButtonsVisible + */ + bool areOpenCloseButtonsVisible() const throw() { return openCloseButtonsVisible; } -/** - A text editor component designed specifically for source code. + /** Deselects any items that are currently selected. */ + void clearSelectedItems(); - This is designed to handle syntax highlighting and fast editing of very large - files. -*/ -class JUCE_API CodeEditorComponent : public Component, - public Timer, - public ScrollBarListener, - public CodeDocument::Listener, - public AsyncUpdater -{ -public: + /** Returns the number of items that are currently selected. - /** Creates an editor for a document. + @see getSelectedItem, clearSelectedItems + */ + int getNumSelectedItems() const throw(); - The tokeniser object is optional - pass 0 to disable syntax highlighting. - The object that you pass in is not owned or deleted by the editor - you must - make sure that it doesn't get deleted while this component is still using it. + /** Returns one of the selected items in the tree. - @see CodeDocument + @param index the index, 0 to (getNumSelectedItems() - 1) */ - CodeEditorComponent (CodeDocument& document, - CodeTokeniser* const codeTokeniser); + TreeViewItem* getSelectedItem (const int index) const throw(); - /** Destructor. */ - ~CodeEditorComponent(); + /** Returns the number of rows the tree is using. - /** Returns the code document that this component is editing. */ - CodeDocument& getDocument() const throw() { return document; } + This will depend on which items are open. - /** Loads the given content into the document. - This will completely reset the CodeDocument object, clear its undo history, - and fill it with this text. + @see TreeViewItem::getRowNumberInTree() */ - void loadContent (const String& newContent); + int getNumRowsInTree() const; - /** Returns the standard character width. */ - float getCharWidth() const throw() { return charWidth; } + /** Returns the item on a particular row of the tree. - /** Returns the height of a line of text, in pixels. */ - int getLineHeight() const throw() { return lineHeight; } + If the index is out of range, this will return 0. - /** Returns the number of whole lines visible on the screen, - This doesn't include a cut-off line that might be visible at the bottom if the - component's height isn't an exact multiple of the line-height. + @see getNumRowsInTree, TreeViewItem::getRowNumberInTree() */ - int getNumLinesOnScreen() const throw() { return linesOnScreen; } + TreeViewItem* getItemOnRow (int index) const; - /** Returns the number of whole columns visible on the screen. - This doesn't include any cut-off columns at the right-hand edge. + /** Returns the item that contains a given y position. + The y is relative to the top of the TreeView component. */ - int getNumColumnsOnScreen() const throw() { return columnsOnScreen; } + TreeViewItem* getItemAt (int yPosition) const throw(); - /** Returns the current caret position. */ - const CodeDocument::Position getCaretPos() const { return caretPos; } + /** Tries to scroll the tree so that this item is on-screen somewhere. */ + void scrollToKeepItemVisible (TreeViewItem* item); - /** Moves the caret. - If selecting is true, the section of the document between the current - caret position and the new one will become selected. If false, any currently - selected region will be deselected. - */ - void moveCaretTo (const CodeDocument::Position& newPos, const bool selecting); + /** Returns the treeview's Viewport object. */ + Viewport* getViewport() const throw() { return viewport; } - /** Returns the on-screen position of a character in the document. - The rectangle returned is relative to this component's top-left origin. + /** Returns the number of pixels by which each nested level of the tree is indented. + @see setIndentSize */ - const Rectangle getCharacterBounds (const CodeDocument::Position& pos) const throw(); + int getIndentSize() const throw() { return indentSize; } - /** Finds the character at a given on-screen position. - The co-ordinates are relative to this component's top-left origin. + /** Changes the distance by which each nested level of the tree is indented. + @see getIndentSize */ - const CodeDocument::Position getPositionAt (int x, int y); - - void cursorLeft (const bool moveInWholeWordSteps, const bool selecting); - void cursorRight (const bool moveInWholeWordSteps, const bool selecting); - void cursorDown (const bool selecting); - void cursorUp (const bool selecting); - - void pageDown (const bool selecting); - void pageUp (const bool selecting); - - void scrollDown(); - void scrollUp(); - void scrollToLine (int newFirstLineOnScreen); - void scrollBy (int deltaLines); - void scrollToColumn (int newFirstColumnOnScreen); - void scrollToKeepCaretOnScreen(); - - void goToStartOfDocument (const bool selecting); - void goToStartOfLine (const bool selecting); - void goToEndOfDocument (const bool selecting); - void goToEndOfLine (const bool selecting); - - void deselectAll(); - void selectAll(); - - void insertTextAtCaret (const String& textToInsert); - void insertTabAtCaret(); - void cut(); - void copy(); - void copyThenCut(); - void paste(); - void backspace (const bool moveInWholeWordSteps); - void deleteForward (const bool moveInWholeWordSteps); - - void undo(); - void redo(); + void setIndentSize (const int newIndentSize); - /** Changes the current tab settings. - This lets you change the tab size and whether pressing the tab key inserts a - tab character, or its equivalent number of spaces. + /** Searches the tree for an item with the specified identifier. + The identifer string must have been created by calling TreeViewItem::getItemIdentifierString(). + If no such item exists, this will return false. If the item is found, all of its items + will be automatically opened. */ - void setTabSize (const int numSpacesPerTab, - const bool insertSpacesInsteadOfTabCharacters) throw(); + TreeViewItem* findItemFromIdentifierString (const String& identifierString) const; - /** Returns the current number of spaces per tab. - @see setTabSize - */ - int getTabSize() const throw() { return spacesPerTab; } + /** Saves the current state of open/closed nodes so it can be restored later. - /** Returns true if the tab key will insert spaces instead of actual tab characters. - @see setTabSize - */ - bool areSpacesInsertedForTabs() const { return useSpacesForTabs; } + This takes a snapshot of which nodes have been explicitly opened or closed, + and records it as XML. To identify node objects it uses the + TreeViewItem::getUniqueName() method to create named paths. This + means that the same state of open/closed nodes can be restored to a + completely different instance of the tree, as long as it contains nodes + whose unique names are the same. - /** Changes the font. - Make sure you only use a fixed-width font, or this component will look pretty nasty! - */ - void setFont (const Font& newFont); + The caller is responsible for deleting the object that is returned. - /** Resets the syntax highlighting colours to the default ones provided by the - code tokeniser. - @see CodeTokeniser::getDefaultColour + @param alsoIncludeScrollPosition if this is true, the state will also + include information about where the + tree has been scrolled to vertically, + so this can also be restored + @see restoreOpennessState */ - void resetToDefaultColours(); + XmlElement* getOpennessState (const bool alsoIncludeScrollPosition) const; - /** Changes one of the syntax highlighting colours. - The token type values are dependent on the tokeniser being used - use - CodeTokeniser::getTokenTypes() to get a list of the token types. - @see getColourForTokenType - */ - void setColourForTokenType (const int tokenType, const Colour& colour); + /** Restores a previously saved arrangement of open/closed nodes. - /** Returns one of the syntax highlighting colours. - The token type values are dependent on the tokeniser being used - use - CodeTokeniser::getTokenTypes() to get a list of the token types. - @see setColourForTokenType + This will try to restore a snapshot of the tree's state that was created by + the getOpennessState() method. If any of the nodes named in the original + XML aren't present in this tree, they will be ignored. + + @see getOpennessState */ - const Colour getColourForTokenType (const int tokenType) const throw(); + void restoreOpennessState (const XmlElement& newState); - /** A set of colour IDs to use to change the colour of various aspects of the editor. + /** A set of colour IDs to use to change the colour of various aspects of the treeview. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @@ -45459,2784 +44717,2503 @@ public: */ enum ColourIds { - backgroundColourId = 0x1004500, /**< A colour to use to fill the editor's background. */ - caretColourId = 0x1004501, /**< The colour to draw the caret. */ - highlightColourId = 0x1004502, /**< The colour to use for the highlighted background under - selected text. */ - defaultTextColourId = 0x1004503 /**< The colour to use for text when no syntax colouring is - enabled. */ + backgroundColourId = 0x1000500, /**< A background colour to fill the component with. */ + linesColourId = 0x1000501, /**< The colour to draw the lines with.*/ + dragAndDropIndicatorColourId = 0x1000502 /**< The colour to use for the drag-and-drop target position indicator. */ }; - /** Changes the size of the scrollbars. */ - void setScrollbarThickness (const int thickness) throw(); - - /** @internal */ - void resized(); /** @internal */ void paint (Graphics& g); /** @internal */ + void resized(); + /** @internal */ bool keyPressed (const KeyPress& key); /** @internal */ - void mouseDown (const MouseEvent& e); + void colourChanged(); /** @internal */ - void mouseDrag (const MouseEvent& e); + void enablementChanged(); /** @internal */ - void mouseUp (const MouseEvent& e); + bool isInterestedInFileDrag (const StringArray& files); /** @internal */ - void mouseDoubleClick (const MouseEvent& e); + void fileDragEnter (const StringArray& files, int x, int y); /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + void fileDragMove (const StringArray& files, int x, int y); /** @internal */ - void timerCallback(); + void fileDragExit (const StringArray& files); /** @internal */ - void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart); + void filesDropped (const StringArray& files, int x, int y); /** @internal */ - void handleAsyncUpdate(); + bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent); /** @internal */ - void codeDocumentChanged (const CodeDocument::Position& affectedTextStart, - const CodeDocument::Position& affectedTextEnd); + void itemDragEnter (const String& sourceDescription, Component* sourceComponent, int x, int y); + /** @internal */ + void itemDragMove (const String& sourceDescription, Component* sourceComponent, int x, int y); + /** @internal */ + void itemDragExit (const String& sourceDescription, Component* sourceComponent); + /** @internal */ + void itemDropped (const String& sourceDescription, Component* sourceComponent, int x, int y); juce_UseDebuggingNewOperator private: - CodeDocument& document; - - Font font; - int firstLineOnScreen, gutter, spacesPerTab; - float charWidth; - int lineHeight, linesOnScreen, columnsOnScreen; - int scrollbarThickness; - bool useSpacesForTabs; - double xOffset; - - CodeDocument::Position caretPos; - CodeDocument::Position selectionStart, selectionEnd; - Component* caret; - ScrollBar* verticalScrollBar; - ScrollBar* horizontalScrollBar; - - enum DragType - { - notDragging, - draggingSelectionStart, - draggingSelectionEnd - }; - - DragType dragType; - - CodeTokeniser* codeTokeniser; - Array coloursForTokenCategories; - - OwnedArray lines; - void rebuildLineTokens(); - - OwnedArray cachedIterators; - void clearCachedIterators (const int firstLineToBeInvalid) throw(); - void updateCachedIterators (int maxLineNum); - void getIteratorForPosition (int position, CodeDocument::Iterator& result); - - void updateScrollBars(); - void scrollToLineInternal (int line); - void scrollToColumnInternal (double column); - void newTransaction(); + friend class TreeViewItem; + friend class TreeViewContentComponent; + Viewport* viewport; + CriticalSection nodeAlterationLock; + TreeViewItem* rootItem; + Component* dragInsertPointHighlight; + Component* dragTargetGroupHighlight; + int indentSize; + bool defaultOpenness : 1; + bool needsRecalculating : 1; + bool rootItemVisible : 1; + bool multiSelectEnabled : 1; + bool openCloseButtonsVisible : 1; - int indexToColumn (int line, int index) const throw(); - int columnToIndex (int line, int column) const throw(); + void itemsChanged() throw(); + void handleAsyncUpdate(); + void moveSelectedRow (int delta); + void updateButtonUnderMouse (const MouseEvent& e); + void showDragHighlight (TreeViewItem* item, int insertIndex, int x, int y) throw(); + void hideDragHighlight() throw(); + void handleDrag (const StringArray& files, const String& sourceDescription, Component* sourceComponent, int x, int y); + void handleDrop (const StringArray& files, const String& sourceDescription, Component* sourceComponent, int x, int y); + TreeViewItem* getInsertPosition (int& x, int& y, int& insertIndex, + const StringArray& files, const String& sourceDescription, + Component* sourceComponent) const throw(); - CodeEditorComponent (const CodeEditorComponent&); - const CodeEditorComponent& operator= (const CodeEditorComponent&); + TreeView (const TreeView&); + const TreeView& operator= (const TreeView&); }; -#endif // __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_CodeEditorComponent.h *********/ +#endif // __JUCE_TREEVIEW_JUCEHEADER__ +/********* End of inlined file: juce_TreeView.h *********/ #endif -#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ +#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_CPlusPlusCodeTokeniser.h *********/ -#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ -#define __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ +/********* Start of inlined file: juce_DirectoryContentsDisplayComponent.h *********/ +#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ +#define __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_DirectoryContentsList.h *********/ +#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ +#define __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ + +/********* Start of inlined file: juce_FileFilter.h *********/ +#ifndef __JUCE_FILEFILTER_JUCEHEADER__ +#define __JUCE_FILEFILTER_JUCEHEADER__ /** - A simple lexical analyser for syntax colouring of C++ code. + Interface for deciding which files are suitable for something. - @see SyntaxAnalyser, CodeEditorComponent, CodeDocument + For example, this is used by DirectoryContentsList to select which files + go into the list. + + @see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent */ -class JUCE_API CPlusPlusCodeTokeniser : public CodeTokeniser +class JUCE_API FileFilter { public: - CPlusPlusCodeTokeniser(); - ~CPlusPlusCodeTokeniser(); - - enum TokenType - { - tokenType_error = 0, - tokenType_comment, - tokenType_builtInKeyword, - tokenType_identifier, - tokenType_integerLiteral, - tokenType_floatLiteral, - tokenType_stringLiteral, - tokenType_operator, - tokenType_bracket, - tokenType_punctuation, - tokenType_preprocessor - }; + /** Creates a filter with the given description. - int readNextToken (CodeDocument::Iterator& source); - const StringArray getTokenTypes(); - const Colour getDefaultColour (const int tokenType); + The description can be returned later with the getDescription() method. + */ + FileFilter (const String& filterDescription); - juce_UseDebuggingNewOperator -}; + /** Destructor. */ + virtual ~FileFilter(); -#endif // __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ -/********* End of inlined file: juce_CPlusPlusCodeTokeniser.h *********/ + /** Returns the description that the filter was created with. */ + const String& getDescription() const throw(); -#endif -#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ + /** Should return true if this file is suitable for inclusion in whatever context + the object is being used. + */ + virtual bool isFileSuitable (const File& file) const = 0; -#endif -#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ + /** Should return true if this directory is suitable for inclusion in whatever context + the object is being used. + */ + virtual bool isDirectorySuitable (const File& file) const = 0; -#endif -#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__ +protected: -/********* Start of inlined file: juce_MenuBarComponent.h *********/ -#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__ -#define __JUCE_MENUBARCOMPONENT_JUCEHEADER__ + String description; +}; -/********* Start of inlined file: juce_MenuBarModel.h *********/ -#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__ -#define __JUCE_MENUBARMODEL_JUCEHEADER__ +#endif // __JUCE_FILEFILTER_JUCEHEADER__ +/********* End of inlined file: juce_FileFilter.h *********/ -class MenuBarModel; +/********* Start of inlined file: juce_Image.h *********/ +#ifndef __JUCE_IMAGE_JUCEHEADER__ +#define __JUCE_IMAGE_JUCEHEADER__ /** - A class to receive callbacks when a MenuBarModel changes. + Holds a fixed-size bitmap. - @see MenuBarModel::addListener, MenuBarModel::removeListener, MenuBarModel::menuItemsChanged -*/ -class JUCE_API MenuBarModelListener -{ -public: - /** Destructor. */ - virtual ~MenuBarModelListener() {} + The image is stored in either 24-bit RGB or 32-bit premultiplied-ARGB format. - /** This callback is made when items are changed in the menu bar model. - */ - virtual void menuBarItemsChanged (MenuBarModel* menuBarModel) = 0; + To draw into an image, create a Graphics object for it. + e.g. @code - /** This callback is made when an application command is invoked that - is represented by one of the items in the menu bar model. - */ - virtual void menuCommandInvoked (MenuBarModel* menuBarModel, - const ApplicationCommandTarget::InvocationInfo& info) = 0; -}; + // create a transparent 500x500 image.. + Image myImage (Image::RGB, 500, 500, true); -/** - A class for controlling MenuBar components. + Graphics g (myImage); + g.setColour (Colours::red); + g.fillEllipse (20, 20, 300, 200); // draws a red ellipse in our image. + @endcode - This class is used to tell a MenuBar what menus to show, and to respond - to a menu being selected. + Other useful ways to create an image are with the ImageCache class, or the + ImageFileFormat, which provides a way to load common image files. - @see MenuBarModelListener, MenuBarComponent, PopupMenu + @see Graphics, ImageFileFormat, ImageCache, ImageConvolutionKernel */ -class JUCE_API MenuBarModel : private AsyncUpdater, - private ApplicationCommandManagerListener +class JUCE_API Image { public: - MenuBarModel() throw(); - - /** Destructor. */ - virtual ~MenuBarModel(); - - /** Call this when some of your menu items have changed. + enum PixelFormat + { + RGB, /**<< each pixel is a 3-byte packed RGB colour value. For byte order, see the PixelRGB class. */ + ARGB, /**<< each pixel is a 4-byte ARGB premultiplied colour value. For byte order, see the PixelARGB class. */ + SingleChannel /**<< each pixel is a 1-byte alpha channel value. */ + }; - This method will cause a callback to any MenuBarListener objects that - are registered with this model. + /** Creates an in-memory image with a specified size and format. - If this model is displaying items from an ApplicationCommandManager, you - can use the setApplicationCommandManagerToWatch() method to cause - change messages to be sent automatically when the ApplicationCommandManager - is changed. + To create an image that can use native OS rendering methods, see createNativeImage(). - @see addListener, removeListener, MenuBarListener + @param format the number of colour channels in the image + @param imageWidth the desired width of the image, in pixels - this value must be + greater than zero (otherwise a width of 1 will be used) + @param imageHeight the desired width of the image, in pixels - this value must be + greater than zero (otherwise a height of 1 will be used) + @param clearImage if true, the image will initially be cleared to black or transparent + black. If false, the image may contain random data, and the + user will have to deal with this */ - void menuItemsChanged(); + Image (const PixelFormat format, + const int imageWidth, + const int imageHeight, + const bool clearImage); - /** Tells the menu bar to listen to the specified command manager, and to update - itself when the commands change. + /** Creates a copy of another image. - This will also allow it to flash a menu name when a command from that menu - is invoked using a keystroke. + @see createCopy */ - void setApplicationCommandManagerToWatch (ApplicationCommandManager* const manager) throw(); + Image (const Image& other); - /** Registers a listener for callbacks when the menu items in this model change. + /** Destructor. */ + virtual ~Image(); - The listener object will get callbacks when this object's menuItemsChanged() - method is called. + /** Tries to create an image that is uses native drawing methods when you render + onto it. - @see removeListener + On some platforms this will just return a normal software-based image. */ - void addListener (MenuBarModelListener* const listenerToAdd) throw(); - - /** Removes a listener. + static Image* createNativeImage (const PixelFormat format, + const int imageWidth, + const int imageHeight, + const bool clearImage); - @see addListener + /** Returns the image's width (in pixels). */ + int getWidth() const throw() { return imageWidth; } + + /** Returns the image's height (in pixels). */ + int getHeight() const throw() { return imageHeight; } + + /** Returns a rectangle with the same size as this image. + The rectangle is always at position (0, 0). */ - void removeListener (MenuBarModelListener* const listenerToRemove) throw(); + const Rectangle getBounds() const throw() { return Rectangle (0, 0, imageWidth, imageHeight); } - /** This method must return a list of the names of the menus. */ - virtual const StringArray getMenuBarNames() = 0; + /** Returns the image's pixel format. */ + PixelFormat getFormat() const throw() { return format; } - /** This should return the popup menu to display for a given top-level menu. + /** True if the image's format is ARGB. */ + bool isARGB() const throw() { return format == ARGB; } - @param topLevelMenuIndex the index of the top-level menu to show - @param menuName the name of the top-level menu item to show - */ - virtual const PopupMenu getMenuForIndex (int topLevelMenuIndex, - const String& menuName) = 0; + /** True if the image's format is RGB. */ + bool isRGB() const throw() { return format == RGB; } - /** This is called when a menu item has been clicked on. + /** True if the image contains an alpha-channel. */ + bool hasAlphaChannel() const throw() { return format != RGB; } - @param menuItemID the item ID of the PopupMenu item that was selected - @param topLevelMenuIndex the index of the top-level menu from which the item was - chosen (just in case you've used duplicate ID numbers - on more than one of the popup menus) + /** Clears a section of the image with a given colour. + + This won't do any alpha-blending - it just sets all pixels in the image to + the given colour (which may be non-opaque if the image has an alpha channel). */ - virtual void menuItemSelected (int menuItemID, - int topLevelMenuIndex) = 0; + virtual void clear (int x, int y, int w, int h, + const Colour& colourToClearTo = Colour (0x00000000)); -#if JUCE_MAC || DOXYGEN - /** MAC ONLY - Sets the model that is currently being shown as the main - menu bar at the top of the screen on the Mac. + /** Returns a new image that's a copy of this one. - You can pass 0 to stop the current model being displayed. Be careful - not to delete a model while it is being used. + A new size for the copied image can be specified, or values less than + zero can be passed-in to use the image's existing dimensions. - An optional extra menu can be specified, containing items to add to the top of - the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of - an apple, it's the one next to it, with your application's name at the top - and the services menu etc on it). When one of these items is selected, the - menu bar model will be used to invoke it, and in the menuItemSelected() callback - the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems - object then newMenuBarModel must be non-null. + It's up to the caller to delete the image when no longer needed. */ - static void setMacMainMenu (MenuBarModel* newMenuBarModel, - const PopupMenu* extraAppleMenuItems = 0) throw(); + virtual Image* createCopy (int newWidth = -1, + int newHeight = -1, + const Graphics::ResamplingQuality quality = Graphics::mediumResamplingQuality) const; - /** MAC ONLY - Returns the menu model that is currently being shown as - the main menu bar. + /** Returns a new single-channel image which is a copy of the alpha-channel of this image. */ - static MenuBarModel* getMacMainMenu() throw(); - -#endif + virtual Image* createCopyOfAlphaChannel() const; - /** @internal */ - void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info); - /** @internal */ - void applicationCommandListChanged(); - /** @internal */ - void handleAsyncUpdate(); + /** Returns the colour of one of the pixels in the image. - juce_UseDebuggingNewOperator + If the co-ordinates given are beyond the image's boundaries, this will + return Colours::transparentBlack. -private: - ApplicationCommandManager* manager; - SortedSet listeners; + (0, 0) is the image's top-left corner. - MenuBarModel (const MenuBarModel&); - const MenuBarModel& operator= (const MenuBarModel&); -}; + @see getAlphaAt, setPixelAt, blendPixelAt + */ + virtual const Colour getPixelAt (const int x, const int y) const; -#endif // __JUCE_MENUBARMODEL_JUCEHEADER__ -/********* End of inlined file: juce_MenuBarModel.h *********/ + /** Sets the colour of one of the image's pixels. -/** - A menu bar component. + If the co-ordinates are beyond the image's boundaries, then nothing will + happen. - @see MenuBarModel -*/ -class JUCE_API MenuBarComponent : public Component, - private MenuBarModelListener, - private Timer -{ -public: + Note that unlike blendPixelAt(), this won't do any alpha-blending, it'll + just replace the existing pixel with the given one. The colour's opacity + will be ignored if this image doesn't have an alpha-channel. - /** Creates a menu bar. + (0, 0) is the image's top-left corner. - @param model the model object to use to control this bar. You can - pass 0 into this if you like, and set the model later - using the setModel() method + @see blendPixelAt */ - MenuBarComponent (MenuBarModel* const model); - - /** Destructor. */ - ~MenuBarComponent(); + virtual void setPixelAt (const int x, const int y, const Colour& colour); - /** Changes the model object to use to control the bar. + /** Changes the opacity of a pixel. - This can be 0, in which case the bar will be empty. Don't delete the object - that is passed-in while it's still being used by this MenuBar. - */ - void setModel (MenuBarModel* const newModel); + This only has an effect if the image has an alpha channel and if the + given co-ordinates are inside the image's boundary. - /** Pops up one of the menu items. + The multiplier must be in the range 0 to 1.0, and the current alpha + at the given co-ordinates will be multiplied by this value. - This lets you manually open one of the menus - it could be triggered by a - key shortcut, for example. + @see getAlphaAt, setPixelAt */ - void showMenu (const int menuIndex); + virtual void multiplyAlphaAt (const int x, const int y, const float multiplier); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void mouseEnter (const MouseEvent& e); - /** @internal */ - void mouseExit (const MouseEvent& e); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - void mouseMove (const MouseEvent& e); - /** @internal */ - void inputAttemptWhenModal(); - /** @internal */ - void handleCommandMessage (int commandId); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void menuBarItemsChanged (MenuBarModel* menuBarModel); - /** @internal */ - void menuCommandInvoked (MenuBarModel* menuBarModel, - const ApplicationCommandTarget::InvocationInfo& info); + /** Changes the overall opacity of the image. - juce_UseDebuggingNewOperator + This will multiply the alpha value of each pixel in the image by the given + amount (limiting the resulting alpha values between 0 and 255). This allows + you to make an image more or less transparent. -private: - MenuBarModel* model; + If the image doesn't have an alpha channel, this won't have any effect. + */ + virtual void multiplyAllAlphas (const float amountToMultiplyBy); - StringArray menuNames; - Array xPositions; - int itemUnderMouse, currentPopupIndex, topLevelIndexClicked, indexToShowAgain; - int lastMouseX, lastMouseY; - bool inModalState; - Component* currentPopup; + /** Changes all the colours to be shades of grey, based on their current luminosity. + */ + virtual void desaturate(); - int getItemAt (int x, int y); - void updateItemUnderMouse (const int x, const int y); - void hideCurrentMenu(); - void timerCallback(); - void repaintMenuItem (int index); + /** Retrieves a section of an image as raw pixel data, so it can be read or written to. - MenuBarComponent (const MenuBarComponent&); - const MenuBarComponent& operator= (const MenuBarComponent&); -}; + You should only use this class as a last resort - messing about with the internals of + an image is only recommended for people who really know what they're doing! -#endif // __JUCE_MENUBARCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_MenuBarComponent.h *********/ + A BitmapData object should be used as a temporary, stack-based object. Don't keep one + hanging around while the image is being used elsewhere. -#endif -#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__ + Depending on the way the image class is implemented, this may create a temporary buffer + which is copied back to the image when the object is deleted, or it may just get a pointer + directly into the image's raw data. -#endif -#ifndef __JUCE_POPUPMENU_JUCEHEADER__ + You can use the stride and data values in this class directly, but don't alter them! + The actual format of the pixel data depends on the image's format - see Image::getFormat(), + and the PixelRGB, PixelARGB and PixelAlpha classes for more info. + */ + class BitmapData + { + public: + BitmapData (Image& image, int x, int y, int w, int h, const bool needsToBeWritable) throw(); + BitmapData (const Image& image, int x, int y, int w, int h) throw(); + ~BitmapData() throw(); -#endif -#ifndef __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ + /** Returns a pointer to the start of a line in the image. + The co-ordinate you provide here isn't checked, so it's the caller's responsibility to make + sure it's not out-of-range. + */ + inline uint8* getLinePointer (const int y) const throw() { return data + y * lineStride; } -#endif -#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__ + /** Returns a pointer to a pixel in the image. + The co-ordinates you give here are not checked, so it's the caller's responsibility to make sure they're + not out-of-range. + */ + inline uint8* getPixelPointer (const int x, const int y) const throw() { return data + y * lineStride + x * pixelStride; } -/********* Start of inlined file: juce_ComponentDragger.h *********/ -#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__ -#define __JUCE_COMPONENTDRAGGER_JUCEHEADER__ + uint8* data; + int lineStride, pixelStride, width, height; -/********* Start of inlined file: juce_ComponentBoundsConstrainer.h *********/ -#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ -#define __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ + private: + BitmapData (const BitmapData&); + const BitmapData& operator= (const BitmapData&); + }; -/** - A class that imposes restrictions on a Component's size or position. + /** Copies some pixel values to a rectangle of the image. - This is used by classes such as ResizableCornerComponent, - ResizableBorderComponent and ResizableWindow. + The format of the pixel data must match that of the image itself, and the + rectangle supplied must be within the image's bounds. + */ + virtual void setPixelData (int destX, int destY, int destW, int destH, + const uint8* sourcePixelData, int sourceLineStride); - The base class can impose some basic size and position limits, but you can - also subclass this for custom uses. + /** Copies a section of the image to somewhere else within itself. + */ + virtual void moveImageSection (int destX, int destY, + int sourceX, int sourceY, + int width, int height); - @see ResizableCornerComponent, ResizableBorderComponent, ResizableWindow -*/ -class JUCE_API ComponentBoundsConstrainer -{ -public: + /** Creates a RectangleList containing rectangles for all non-transparent pixels + of the image. - /** When first created, the object will not impose any restrictions on the components. */ - ComponentBoundsConstrainer() throw(); + @param result the list that will have the area added to it + @param alphaThreshold for a semi-transparent image, any pixels whose alpha is + above this level will be considered opaque + */ + void createSolidAreaMask (RectangleList& result, + const float alphaThreshold = 0.5f) const; - /** Destructor. */ - virtual ~ComponentBoundsConstrainer(); + juce_UseDebuggingNewOperator - /** Imposes a minimum width limit. */ - void setMinimumWidth (const int minimumWidth) throw(); + /** Creates a context suitable for drawing onto this image. - /** Returns the current minimum width. */ - int getMinimumWidth() const throw() { return minW; } + Don't call this method directly! It's used internally by the Graphics class. + */ + virtual LowLevelGraphicsContext* createLowLevelContext(); - /** Imposes a maximum width limit. */ - void setMaximumWidth (const int maximumWidth) throw(); +protected: + friend class BitmapData; + const PixelFormat format; + const int imageWidth, imageHeight; - /** Returns the current maximum width. */ - int getMaximumWidth() const throw() { return maxW; } + /** Used internally so that subclasses can call a constructor that doesn't allocate memory */ + Image (const PixelFormat format, + const int imageWidth, + const int imageHeight); - /** Imposes a minimum height limit. */ - void setMinimumHeight (const int minimumHeight) throw(); + int pixelStride, lineStride; + HeapBlock imageDataAllocated; + uint8* imageData; - /** Returns the current minimum height. */ - int getMinimumHeight() const throw() { return minH; } +private: - /** Imposes a maximum height limit. */ - void setMaximumHeight (const int maximumHeight) throw(); + const Image& operator= (const Image&); +}; - /** Returns the current maximum height. */ - int getMaximumHeight() const throw() { return maxH; } +#endif // __JUCE_IMAGE_JUCEHEADER__ +/********* End of inlined file: juce_Image.h *********/ - /** Imposes a minimum width and height limit. */ - void setMinimumSize (const int minimumWidth, - const int minimumHeight) throw(); +/** + A class to asynchronously scan for details about the files in a directory. - /** Imposes a maximum width and height limit. */ - void setMaximumSize (const int maximumWidth, - const int maximumHeight) throw(); + This keeps a list of files and some information about them, using a background + thread to scan for more files. As files are found, it broadcasts change messages + to tell any listeners. - /** Set all the maximum and minimum dimensions. */ - void setSizeLimits (const int minimumWidth, - const int minimumHeight, - const int maximumWidth, - const int maximumHeight) throw(); + @see FileListComponent, FileBrowserComponent +*/ +class JUCE_API DirectoryContentsList : public ChangeBroadcaster, + public TimeSliceClient +{ +public: - /** Sets the amount by which the component is allowed to go off-screen. + /** Creates a directory list. - The values indicate how many pixels must remain on-screen when dragged off - one of its parent's edges, so e.g. if minimumWhenOffTheTop is set to 10, then - when the component goes off the top of the screen, its y-position will be - clipped so that there are always at least 10 pixels on-screen. In other words, - the lowest y-position it can take would be (10 - the component's height). + To set the directory it should point to, use setDirectory(), which will + also start it scanning for files on the background thread. - If you pass 0 or less for one of these amounts, the component is allowed - to move beyond that edge completely, with no restrictions at all. + When the background thread finds and adds new files to this list, the + ChangeBroadcaster class will send a change message, so you can register + listeners and update them when the list changes. - If you pass a very large number (i.e. larger that the dimensions of the - component itself), then the component won't be allowed to overlap that - edge at all. So e.g. setting minimumWhenOffTheLeft to 0xffffff will mean that - the component will bump into the left side of the screen and go no further. + @param fileFilter an optional filter to select which files are + included in the list. If this is 0, then all files + and directories are included. Make sure that the + filter doesn't get deleted during the lifetime of this + object + @param threadToUse a thread object that this list can use + to scan for files as a background task. Make sure + that the thread you give it has been started, or you + won't get any files! */ - void setMinimumOnscreenAmounts (const int minimumWhenOffTheTop, - const int minimumWhenOffTheLeft, - const int minimumWhenOffTheBottom, - const int minimumWhenOffTheRight) throw(); - - /** Specifies a width-to-height ratio that the resizer should always maintain. - - If the value is 0, no aspect ratio is enforced. If it's non-zero, the width - will always be maintained as this multiple of the height. + DirectoryContentsList (const FileFilter* const fileFilter, + TimeSliceThread& threadToUse); - @see setResizeLimits - */ - void setFixedAspectRatio (const double widthOverHeight) throw(); + /** Destructor. */ + ~DirectoryContentsList(); - /** Returns the aspect ratio that was set with setFixedAspectRatio(). + /** Sets the directory to look in for files. - If no aspect ratio is being enforced, this will return 0. + If the directory that's passed in is different to the current one, this will + also start the background thread scanning it for files. */ - double getFixedAspectRatio() const throw(); + void setDirectory (const File& directory, + const bool includeDirectories, + const bool includeFiles); - /** This callback changes the given co-ordinates to impose whatever the current - constraints are set to be. + /** Returns the directory that's currently being used. */ + const File& getDirectory() const throw(); - @param x the x position that should be examined and adjusted - @param y the y position that should be examined and adjusted - @param w the width that should be examined and adjusted - @param h the height that should be examined and adjusted - @param previousBounds the component's current size - @param limits the region in which the component can be positioned - @param isStretchingTop whether the top edge of the component is being resized - @param isStretchingLeft whether the left edge of the component is being resized - @param isStretchingBottom whether the bottom edge of the component is being resized - @param isStretchingRight whether the right edge of the component is being resized - */ - virtual void checkBounds (int& x, int& y, int& w, int& h, - const Rectangle& previousBounds, - const Rectangle& limits, - const bool isStretchingTop, - const bool isStretchingLeft, - const bool isStretchingBottom, - const bool isStretchingRight); + /** Clears the list, and stops the thread scanning for files. */ + void clear(); - /** This callback happens when the resizer is about to start dragging. */ - virtual void resizeStart(); + /** Clears the list and restarts scanning the directory for files. */ + void refresh(); - /** This callback happens when the resizer has finished dragging. */ - virtual void resizeEnd(); + /** True if the background thread hasn't yet finished scanning for files. */ + bool isStillLoading() const; - /** Checks the given bounds, and then sets the component to the corrected size. */ - void setBoundsForComponent (Component* const component, - int x, int y, int w, int h, - const bool isStretchingTop, - const bool isStretchingLeft, - const bool isStretchingBottom, - const bool isStretchingRight); + /** Tells the list whether or not to ignore hidden files. - /** Performs a check on the current size of a component, and moves or resizes - it if it fails the constraints. + By default these are ignored. */ - void checkComponentBounds (Component* component); + void setIgnoresHiddenFiles (const bool shouldIgnoreHiddenFiles); - /** Called by setBoundsForComponent() to apply a new constrained size to a - component. + /** Returns true if hidden files are ignored. + @see setIgnoresHiddenFiles + */ + bool ignoresHiddenFiles() const throw() { return ignoreHiddenFiles; } - By default this just calls setBounds(), but it virtual in case it's needed for - extremely cunning purposes. + /** Contains cached information about one of the files in a DirectoryContentsList. */ - virtual void applyBoundsToComponent (Component* component, - int x, int y, int w, int h); + struct FileInfo + { - juce_UseDebuggingNewOperator + /** The filename. -private: - int minW, maxW, minH, maxH; - int minOffTop, minOffLeft, minOffBottom, minOffRight; - double aspectRatio; + This isn't a full pathname, it's just the last part of the path, same as you'd + get from File::getFileName(). - ComponentBoundsConstrainer (const ComponentBoundsConstrainer&); - const ComponentBoundsConstrainer& operator= (const ComponentBoundsConstrainer&); -}; + To get the full pathname, use DirectoryContentsList::getDirectory().getChildFile (filename). + */ + String filename; -#endif // __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ -/********* End of inlined file: juce_ComponentBoundsConstrainer.h *********/ + /** File size in bytes. */ + int64 fileSize; -/** - An object to take care of the logic for dragging components around with the mouse. + /** File modification time. - Very easy to use - in your mouseDown() callback, call startDraggingComponent(), - then in your mouseDrag() callback, call dragComponent(). + As supplied by File::getLastModificationTime(). + */ + Time modificationTime; - When starting a drag, you can give it a ComponentBoundsConstrainer to use - to limit the component's position and keep it on-screen. + /** File creation time. - e.g. @code - class MyDraggableComp - { - ComponentDragger myDragger; + As supplied by File::getCreationTime(). + */ + Time creationTime; - void mouseDown (const MouseEvent& e) - { - myDragger.startDraggingComponent (this, 0); - } + /** True if the file is a directory. */ + bool isDirectory; - void mouseDrag (const MouseEvent& e) - { - myDragger.dragComponent (this, e); - } + /** True if the file is read-only. */ + bool isReadOnly; }; - @endcode -*/ -class JUCE_API ComponentDragger -{ -public: - /** Creates a ComponentDragger. */ - ComponentDragger(); + /** Returns the number of files currently available in the list. - /** Destructor. */ - virtual ~ComponentDragger(); + The info about one of these files can be retrieved with getFileInfo() or + getFile(). - /** Call this from your component's mouseDown() method, to prepare for dragging. + Obviously as the background thread runs and scans the directory for files, this + number will change. - @param componentToDrag the component that you want to drag - @param constrainer a constrainer object to use to keep the component - from going offscreen - @see dragComponent + @see getFileInfo, getFile */ - void startDraggingComponent (Component* const componentToDrag, - ComponentBoundsConstrainer* constrainer); + int getNumFiles() const; - /** Call this from your mouseDrag() callback to move the component. + /** Returns the cached information about one of the files in the list. - This will move the component, but will first check the validity of the - component's new position using the checkPosition() method, which you - can override if you need to enforce special positioning limits on the - component. + If the index is in-range, this will return true and will copy the file's details + to the structure that is passed-in. - @param componentToDrag the component that you want to drag - @param e the current mouse-drag event - @see dragComponent + If it returns false, then the index wasn't in range, and the structure won't + be affected. + + @see getNumFiles, getFile */ - void dragComponent (Component* const componentToDrag, - const MouseEvent& e); + bool getFileInfo (const int index, + FileInfo& resultInfo) const; - juce_UseDebuggingNewOperator + /** Returns one of the files in the list. -private: - ComponentBoundsConstrainer* constrainer; - int originalX, originalY; -}; + @param index should be less than getNumFiles(). If this is out-of-range, the + return value will be File::nonexistent + @see getNumFiles, getFileInfo + */ + const File getFile (const int index) const; -#endif // __JUCE_COMPONENTDRAGGER_JUCEHEADER__ -/********* End of inlined file: juce_ComponentDragger.h *********/ + /** Returns the file filter being used. -#endif -#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ + The filter is specified in the constructor. + */ + const FileFilter* getFilter() const throw() { return fileFilter; } -#endif -#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ + /** @internal */ + bool useTimeSlice(); + /** @internal */ + TimeSliceThread& getTimeSliceThread() throw() { return thread; } + /** @internal */ + static int compareElements (const DirectoryContentsList::FileInfo* const first, + const DirectoryContentsList::FileInfo* const second) throw(); -#endif -#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__ + juce_UseDebuggingNewOperator -/********* Start of inlined file: juce_LassoComponent.h *********/ -#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__ -#define __JUCE_LASSOCOMPONENT_JUCEHEADER__ +private: + File root; + const FileFilter* fileFilter; + TimeSliceThread& thread; + bool includeDirectories, includeFiles, ignoreHiddenFiles; -/********* Start of inlined file: juce_SelectedItemSet.h *********/ -#ifndef __JUCE_SELECTEDITEMSET_JUCEHEADER__ -#define __JUCE_SELECTEDITEMSET_JUCEHEADER__ + CriticalSection fileListLock; + OwnedArray files; -/** Manages a list of selectable items. + void* volatile fileFindHandle; + bool volatile shouldStop; - Use one of these to keep a track of things that the user has highlighted, like - icons or things in a list. + void changed(); + bool checkNextFile (bool& hasChanged); + bool addFile (const String& filename, const bool isDir, const bool isHidden, + const int64 fileSize, const Time& modTime, + const Time& creationTime, const bool isReadOnly); - The class is templated so that you can use it to hold either a set of pointers - to objects, or a set of ID numbers or handles, for cases where each item may - not always have a corresponding object. + DirectoryContentsList (const DirectoryContentsList&); + const DirectoryContentsList& operator= (const DirectoryContentsList&); +}; - To be informed when items are selected/deselected, register a ChangeListener with - this object. +#endif // __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ +/********* End of inlined file: juce_DirectoryContentsList.h *********/ - @see SelectableObject +/********* Start of inlined file: juce_FileBrowserListener.h *********/ +#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ +#define __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ + +/** + A listener for user selection events in a file browser. + + This is used by a FileBrowserComponent or FileListComponent. */ -template -class JUCE_API SelectedItemSet : public ChangeBroadcaster +class JUCE_API FileBrowserListener { public: - /** Creates an empty set. */ - SelectedItemSet() - { - } - - /** Creates a set based on an array of items. */ - SelectedItemSet (const Array & items) - : selectedItems (items) - { - } - - /** Creates a copy of another set. */ - SelectedItemSet (const SelectedItemSet& other) - : selectedItems (other.selectedItems) - { - } - - /** Creates a copy of another set. */ - const SelectedItemSet& operator= (const SelectedItemSet& other) - { - if (selectedItems != other.selectedItems) - { - selectedItems = other.selectedItems; - changed(); - } - - return *this; - } - /** Destructor. */ - ~SelectedItemSet() - { - } + virtual ~FileBrowserListener(); - /** Clears any other currently selected items, and selects this item. + /** Callback when the user selects a different file in the browser. */ + virtual void selectionChanged() = 0; - If this item is already the only thing selected, no change notification - will be sent out. + /** Callback when the user clicks on a file in the browser. */ + virtual void fileClicked (const File& file, const MouseEvent& e) = 0; - @see addToSelection, addToSelectionBasedOnModifiers - */ - void selectOnly (SelectableItemType item) - { - if (isSelected (item)) - { - for (int i = selectedItems.size(); --i >= 0;) - { - if (selectedItems.getUnchecked(i) != item) - { - deselect (selectedItems.getUnchecked(i)); - i = jmin (i, selectedItems.size()); - } - } - } - else - { - deselectAll(); - changed(); + /** Callback when the user double-clicks on a file in the browser. */ + virtual void fileDoubleClicked (const File& file) = 0; +}; - selectedItems.add (item); - itemSelected (item); - } - } +#endif // __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ +/********* End of inlined file: juce_FileBrowserListener.h *********/ - /** Selects an item. +/** + A base class for components that display a list of the files in a directory. - If the item is already selected, no change notification will be sent out. + @see DirectoryContentsList +*/ +class JUCE_API DirectoryContentsDisplayComponent +{ +public: - @see selectOnly, addToSelectionBasedOnModifiers + /** */ - void addToSelection (SelectableItemType item) - { - if (! isSelected (item)) - { - changed(); - - selectedItems.add (item); - itemSelected (item); - } - } - - /** Selects or deselects an item. - - This will use the modifier keys to decide whether to deselect other items - first. - - So if the shift key is held down, the item will be added without deselecting - anything (same as calling addToSelection() ) - - If no modifiers are down, the current selection will be cleared first (same - as calling selectOnly() ) + DirectoryContentsDisplayComponent (DirectoryContentsList& listToShow); - If the ctrl (or command on the Mac) key is held down, the item will be toggled - - so it'll be added to the set unless it's already there, in which case it'll be - deselected. + /** Destructor. */ + virtual ~DirectoryContentsDisplayComponent(); - If the items that you're selecting can also be dragged, you may need to use the - addToSelectionOnMouseDown() and addToSelectionOnMouseUp() calls to handle the - subtleties of this kind of usage. + /** Returns the number of files the user has got selected. + @see getSelectedFile + */ + virtual int getNumSelectedFiles() const = 0; - @see selectOnly, addToSelection, addToSelectionOnMouseDown, addToSelectionOnMouseUp + /** Returns one of the files that the user has currently selected. + The index should be in the range 0 to (getNumSelectedFiles() - 1). + @see getNumSelectedFiles */ - void addToSelectionBasedOnModifiers (SelectableItemType item, - const ModifierKeys& modifiers) - { - if (modifiers.isShiftDown()) - { - addToSelection (item); - } - else if (modifiers.isCommandDown()) - { - if (isSelected (item)) - deselect (item); - else - addToSelection (item); - } - else - { - selectOnly (item); - } - } + virtual const File getSelectedFile (int index) const = 0; - /** Selects or deselects items that can also be dragged, based on a mouse-down event. + /** Scrolls this view to the top. */ + virtual void scrollToTop() = 0; - If you call addToSelectionOnMouseDown() at the start of your mouseDown event, - and then call addToSelectionOnMouseUp() at the end of your mouseUp event, this - makes it easy to handle multiple-selection of sets of objects that can also - be dragged. + /** Adds a listener to be told when files are selected or clicked. - For example, if you have several items already selected, and you click on - one of them (without dragging), then you'd expect this to deselect the other, and - just select the item you clicked on. But if you had clicked on this item and - dragged it, you'd have expected them all to stay selected. + @see removeListener + */ + void addListener (FileBrowserListener* const listener) throw(); - When you call this method, you'll need to store the boolean result, because the - addToSelectionOnMouseUp() method will need to be know this value. + /** Removes a listener. - @see addToSelectionOnMouseUp, addToSelectionBasedOnModifiers + @see addListener */ - bool addToSelectionOnMouseDown (SelectableItemType item, - const ModifierKeys& modifiers) - { - if (isSelected (item)) - { - return ! modifiers.isPopupMenu(); - } - else - { - addToSelectionBasedOnModifiers (item, modifiers); - return false; - } - } + void removeListener (FileBrowserListener* const listener) throw(); - /** Selects or deselects items that can also be dragged, based on a mouse-up event. + /** A set of colour IDs to use to change the colour of various aspects of the label. - Call this during a mouseUp callback, when you have previously called the - addToSelectionOnMouseDown() method during your mouseDown event. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - See addToSelectionOnMouseDown() for more info + Note that you can also use the constants from TextEditor::ColourIds to change the + colour of the text editor that is opened when a label is editable. - @param item the item to select (or deselect) - @param modifiers the modifiers from the mouse-up event - @param wasItemDragged true if your item was dragged during the mouse click - @param resultOfMouseDownSelectMethod this is the boolean return value that came - back from the addToSelectionOnMouseDown() call that you - should have made during the matching mouseDown event + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void addToSelectionOnMouseUp (SelectableItemType item, - const ModifierKeys& modifiers, - const bool wasItemDragged, - const bool resultOfMouseDownSelectMethod) + enum ColourIds { - if (resultOfMouseDownSelectMethod && ! wasItemDragged) - addToSelectionBasedOnModifiers (item, modifiers); - } + highlightColourId = 0x1000540, /**< The colour to use to fill a highlighted row of the list. */ + textColourId = 0x1000541, /**< The colour for the text. */ + }; - /** Deselects an item. */ - void deselect (SelectableItemType item) - { - const int i = selectedItems.indexOf (item); + /** @internal */ + void sendSelectionChangeMessage(); + /** @internal */ + void sendDoubleClickMessage (const File& file); + /** @internal */ + void sendMouseClickMessage (const File& file, const MouseEvent& e); - if (i >= 0) - { - changed(); - itemDeselected (selectedItems.remove (i)); - } - } + juce_UseDebuggingNewOperator - /** Deselects all items. */ - void deselectAll() - { - if (selectedItems.size() > 0) - { - changed(); +protected: + DirectoryContentsList& fileList; + SortedSet listeners; - for (int i = selectedItems.size(); --i >= 0;) - { - itemDeselected (selectedItems.remove (i)); - i = jmin (i, selectedItems.size()); - } - } - } + DirectoryContentsDisplayComponent (const DirectoryContentsDisplayComponent&); + const DirectoryContentsDisplayComponent& operator= (const DirectoryContentsDisplayComponent&); +}; - /** Returns the number of currently selected items. +#endif // __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_DirectoryContentsDisplayComponent.h *********/ - @see getSelectedItem - */ - int getNumSelected() const throw() - { - return selectedItems.size(); - } +#endif +#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ - /** Returns one of the currently selected items. +#endif +#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ - Returns 0 if the index is out-of-range. +/********* Start of inlined file: juce_FileBrowserComponent.h *********/ +#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ +#define __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ - @see getNumSelected - */ - SelectableItemType getSelectedItem (const int index) const throw() - { - return selectedItems [index]; - } +/********* Start of inlined file: juce_FilePreviewComponent.h *********/ +#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ +#define __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ - /** True if this item is currently selected. */ - bool isSelected (const SelectableItemType item) const throw() - { - return selectedItems.contains (item); - } +/** + Base class for components that live inside a file chooser dialog box and + show previews of the files that get selected. - const Array & getItemArray() const throw() { return selectedItems; } + One of these allows special extra information to be displayed for files + in a dialog box as the user selects them. Each time the current file or + directory is changed, the selectedFileChanged() method will be called + to allow it to update itself appropriately. - /** Can be overridden to do special handling when an item is selected. + @see FileChooser, ImagePreviewComponent +*/ +class JUCE_API FilePreviewComponent : public Component +{ +public: - For example, if the item is an object, you might want to call it and tell - it that it's being selected. - */ - virtual void itemSelected (SelectableItemType item) {} + /** Creates a FilePreviewComponent. */ + FilePreviewComponent(); - /** Can be overridden to do special handling when an item is deselected. + /** Destructor. */ + ~FilePreviewComponent(); - For example, if the item is an object, you might want to call it and tell - it that it's being deselected. - */ - virtual void itemDeselected (SelectableItemType item) {} + /** Called to indicate that the user's currently selected file has changed. - /** Used internally, but can be called to force a change message to be sent to the ChangeListeners. + @param newSelectedFile the newly selected file or directory, which may be + File::nonexistent if none is selected. */ - void changed (const bool synchronous = false) - { - if (synchronous) - sendSynchronousChangeMessage (this); - else - sendChangeMessage (this); - } + virtual void selectedFileChanged (const File& newSelectedFile) = 0; juce_UseDebuggingNewOperator private: - Array selectedItems; + FilePreviewComponent (const FilePreviewComponent&); + const FilePreviewComponent& operator= (const FilePreviewComponent&); }; -#endif // __JUCE_SELECTEDITEMSET_JUCEHEADER__ -/********* End of inlined file: juce_SelectedItemSet.h *********/ +#endif // __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FilePreviewComponent.h *********/ /** - A class used by the LassoComponent to manage the things that it selects. + A component for browsing and selecting a file or directory to open or save. - This allows the LassoComponent to find out which items are within the lasso, - and to change the list of selected items. + This contains a FileListComponent and adds various boxes and controls for + navigating and selecting a file. It can work in different modes so that it can + be used for loading or saving a file, or for choosing a directory. - @see LassoComponent, SelectedItemSet + @see FileChooserDialogBox, FileChooser, FileListComponent */ -template -class LassoSource +class JUCE_API FileBrowserComponent : public Component, + public ChangeBroadcaster, + private FileBrowserListener, + private TextEditorListener, + private ButtonListener, + private ComboBoxListener, + private FileFilter { public: - /** Destructor. */ - virtual ~LassoSource() {} - /** Returns the set of items that lie within a given lassoable region. - - Your implementation of this method must find all the relevent items that lie - within the given rectangle. and add them to the itemsFound array. + /** Various options for the browser. - The co-ordinates are relative to the top-left of the lasso component's parent - component. (i.e. they are the same as the size and position of the lasso - component itself). + A combination of these is passed into the FileBrowserComponent constructor. */ - virtual void findLassoItemsInArea (Array & itemsFound, - int x, int y, int width, int height) = 0; + enum FileChooserFlags + { + openMode = 1, /**< specifies that the component should allow the user to + choose an existing file with the intention of opening it. */ + saveMode = 2, /**< specifies that the component should allow the user to specify + the name of a file that will be used to save something. */ + canSelectFiles = 4, /**< specifies that the user can select files (can be used in + conjunction with canSelectDirectories). */ + canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in + conjuction with canSelectFiles). */ + canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ + useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ + filenameBoxIsReadOnly = 64 /**< specifies that the user can't type directly into the filename box. */ + }; - /** Returns the SelectedItemSet that the lasso should update. + /** Creates a FileBrowserComponent. - This set will be continuously updated by the LassoComponent as it gets - dragged around, so make sure that you've got a ChangeListener attached to - the set so that your UI objects will know when the selection changes and - be able to update themselves appropriately. + @param flags A combination of flags from the FileChooserFlags enumeration, + used to specify the component's behaviour. The flags must contain + either openMode or saveMode, and canSelectFiles and/or + canSelectDirectories. + @param initialFileOrDirectory The file or directory that should be selected when + the component begins. If this is File::nonexistent, + a default directory will be chosen. + @param fileFilter an optional filter to use to determine which files + are shown. If this is 0 then all files are displayed. Note + that a pointer is kept internally to this object, so + make sure that it is not deleted before the browser object + is deleted. + @param previewComp an optional preview component that will be used to + show previews of files that the user selects */ - virtual SelectedItemSet & getLassoSelection() = 0; -}; + FileBrowserComponent (int flags, + const File& initialFileOrDirectory, + const FileFilter* fileFilter, + FilePreviewComponent* previewComp); -/** - A component that acts as a rectangular selection region, which you drag with - the mouse to select groups of objects (in conjunction with a SelectedItemSet). + /** Destructor. */ + ~FileBrowserComponent(); - To use one of these: + /** Returns the number of files that the user has got selected. + If multiple select isn't active, this will only be 0 or 1. To get the complete + list of files they've chosen, pass an index to getCurrentFile(). + */ + int getNumSelectedFiles() const throw(); - - In your mouseDown or mouseDrag event, add the LassoComponent to your parent - component, and call its beginLasso() method, giving it a - suitable LassoSource object that it can use to find out which items are in - the active area. + /** Returns one of the files that the user has chosen. + If the box has multi-select enabled, the index lets you specify which of the files + to get - see getNumSelectedFiles() to find out how many files were chosen. + @see getHighlightedFile + */ + const File getSelectedFile (int index) const throw(); - - Each time your parent component gets a mouseDrag event, call dragLasso() - to update the lasso's position - it will use its LassoSource to calculate and - update the current selection. + /** Returns true if the currently selected file(s) are usable. - - After the drag has finished and you get a mouseUp callback, you should call - endLasso() to clean up. This will make the lasso component invisible, and you - can remove it from the parent component, or delete it. + This can be used to decide whether the user can press "ok" for the + current file. What it does depends on the mode, so for example in an "open" + mode, this only returns true if a file has been selected and if it exists. + In a "save" mode, a non-existent file would also be valid. + */ + bool currentFileIsValid() const; - The class takes into account the modifier keys that are being held down while - the lasso is being dragged, so if shift is pressed, then any lassoed items will - be added to the original selection; if ctrl or command is pressed, they will be - xor'ed with any previously selected items. - - @see LassoSource, SelectedItemSet -*/ -template -class LassoComponent : public Component -{ -public: - - /** Creates a Lasso component. - - The fill colour is used to fill the lasso'ed rectangle, and the outline - colour is used to draw a line around its edge. - */ - LassoComponent (const int outlineThickness_ = 1) - : source (0), - outlineThickness (outlineThickness_) - { - } - - /** Destructor. */ - ~LassoComponent() - { - } - - /** Call this in your mouseDown event, to initialise a drag. - - Pass in a suitable LassoSource object which the lasso will use to find - the items and change the selection. - - After using this method to initialise the lasso, repeatedly call dragLasso() - in your component's mouseDrag callback. - - @see dragLasso, endLasso, LassoSource + /** This returns the last item in the view that the user has highlighted. + This may be different from getCurrentFile(), which returns the value + that is shown in the filename box, and if there are multiple selections, + this will only return one of them. + @see getCurrentFile */ - void beginLasso (const MouseEvent& e, - LassoSource * const lassoSource) - { - jassert (source == 0); // this suggests that you didn't call endLasso() after the last drag... - jassert (lassoSource != 0); // the source can't be null! - jassert (getParentComponent() != 0); // you need to add this to a parent component for it to work! - - source = lassoSource; + const File getHighlightedFile() const throw(); - if (lassoSource != 0) - originalSelection = lassoSource->getLassoSelection().getItemArray(); + /** Returns the directory whose contents are currently being shown in the listbox. */ + const File getRoot() const; - setSize (0, 0); - } + /** Changes the directory that's being shown in the listbox. */ + void setRoot (const File& newRootDirectory); - /** Call this in your mouseDrag event, to update the lasso's position. + /** Equivalent to pressing the "up" button to browse the parent directory. */ + void goUp(); - This must be repeatedly calling when the mouse is dragged, after you've - first initialised the lasso with beginLasso(). + /** Refreshes the directory that's currently being listed. */ + void refresh(); - This method takes into account the modifier keys that are being held down, so - if shift is pressed, then the lassoed items will be added to any that were - previously selected; if ctrl or command is pressed, then they will be xor'ed - with previously selected items. + /** Returns a verb to describe what should happen when the file is accepted. - @see beginLasso, endLasso + E.g. if browsing in "load file" mode, this will be "Open", if in "save file" + mode, it'll be "Save", etc. */ - void dragLasso (const MouseEvent& e) - { - if (source != 0) - { - const int x1 = e.getMouseDownX(); - const int y1 = e.getMouseDownY(); - - setBounds (jmin (x1, e.x), jmin (y1, e.y), abs (e.x - x1), abs (e.y - y1)); - setVisible (true); - - Array itemsInLasso; - source->findLassoItemsInArea (itemsInLasso, getX(), getY(), getWidth(), getHeight()); + virtual const String getActionVerb() const; - if (e.mods.isShiftDown()) - { - itemsInLasso.removeValuesIn (originalSelection); // to avoid duplicates - itemsInLasso.addArray (originalSelection); - } - else if (e.mods.isCommandDown() || e.mods.isAltDown()) - { - Array originalMinusNew (originalSelection); - originalMinusNew.removeValuesIn (itemsInLasso); + /** Returns true if the saveMode flag was set when this component was created. + */ + bool isSaveMode() const throw(); - itemsInLasso.removeValuesIn (originalSelection); - itemsInLasso.addArray (originalMinusNew); - } + /** Adds a listener to be told when the user selects and clicks on files. - source->getLassoSelection() = SelectedItemSet (itemsInLasso); - } - } + @see removeListener + */ + void addListener (FileBrowserListener* const listener) throw(); - /** Call this in your mouseUp event, after the lasso has been dragged. + /** Removes a listener. - @see beginLasso, dragLasso + @see addListener */ - void endLasso() - { - source = 0; - originalSelection.clear(); - setVisible (false); - } + void removeListener (FileBrowserListener* const listener) throw(); - /** A set of colour IDs to use to change the colour of various aspects of the label. + /** @internal */ + void resized(); + /** @internal */ + void buttonClicked (Button* b); + /** @internal */ + void comboBoxChanged (ComboBox*); + /** @internal */ + void textEditorTextChanged (TextEditor& editor); + /** @internal */ + void textEditorReturnKeyPressed (TextEditor& editor); + /** @internal */ + void textEditorEscapeKeyPressed (TextEditor& editor); + /** @internal */ + void textEditorFocusLost (TextEditor& editor); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + void selectionChanged(); + /** @internal */ + void fileClicked (const File& f, const MouseEvent& e); + /** @internal */ + void fileDoubleClicked (const File& f); + /** @internal */ + bool isFileSuitable (const File& file) const; + /** @internal */ + bool isDirectorySuitable (const File&) const; - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** @internal */ + FilePreviewComponent* getPreviewComponent() const throw(); - Note that you can also use the constants from TextEditor::ColourIds to change the - colour of the text editor that is opened when a label is editable. + juce_UseDebuggingNewOperator - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - lassoFillColourId = 0x1000440, /**< The colour to fill the lasso rectangle with. */ - lassoOutlineColourId = 0x1000441, /**< The colour to draw the outline with. */ - }; +protected: + virtual const BitArray getRoots (StringArray& rootNames, StringArray& rootPaths); - /** @internal */ - void paint (Graphics& g) - { - g.fillAll (findColour (lassoFillColourId)); +private: - g.setColour (findColour (lassoOutlineColourId)); - g.drawRect (0, 0, getWidth(), getHeight(), outlineThickness); + DirectoryContentsList* fileList; + const FileFilter* fileFilter; - // this suggests that you've left a lasso comp lying around after the - // mouse drag has finished.. Be careful to call endLasso() when you get a - // mouse-up event. - jassert (isMouseButtonDownAnywhere()); - } + int flags; + File currentRoot; + OwnedArray chosenFiles; + SortedSet listeners; - /** @internal */ - bool hitTest (int x, int y) { return false; } + DirectoryContentsDisplayComponent* fileListComponent; + FilePreviewComponent* previewComp; + ComboBox* currentPathBox; + TextEditor* filenameBox; + Button* goUpButton; - juce_UseDebuggingNewOperator + TimeSliceThread thread; -private: - Array originalSelection; - LassoSource * source; - int outlineThickness; -}; + void sendListenerChangeMessage(); + bool isFileOrDirSuitable (const File& f) const; -#endif // __JUCE_LASSOCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_LassoComponent.h *********/ + FileBrowserComponent (const FileBrowserComponent&); + const FileBrowserComponent& operator= (const FileBrowserComponent&); +}; -#endif -#ifndef __JUCE_MOUSECURSOR_JUCEHEADER__ +#endif // __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FileBrowserComponent.h *********/ #endif -#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__ +#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ #endif -#ifndef __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ +#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ -/********* Start of inlined file: juce_MouseHoverDetector.h *********/ -#ifndef __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ -#define __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ +/********* Start of inlined file: juce_FileChooser.h *********/ +#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ +#define __JUCE_FILECHOOSER_JUCEHEADER__ /** - Monitors a component for mouse activity, and triggers a callback - when the mouse hovers in one place for a specified length of time. + Creates a dialog box to choose a file or directory to load or save. - To use a hover-detector, just create one and call its setHoverComponent() - method to start it watching a component. You can call setHoverComponent (0) - to make it inactive. + To use a FileChooser: + - create one (as a local stack variable is the neatest way) + - call one of its browseFor.. methods + - if this returns true, the user has selected a file, so you can retrieve it + with the getResult() method. - (Be careful not to delete a component that's being monitored without first - stopping or deleting the hover detector). + e.g. @code + void loadMooseFile() + { + FileChooser myChooser ("Please select the moose you want to load...", + File::getSpecialLocation (File::userHomeDirectory), + "*.moose"); + + if (myChooser.browseForFileToOpen()) + { + File mooseFile (myChooser.getResult()); + + loadMoose (mooseFile); + } + } + @endcode */ -class JUCE_API MouseHoverDetector +class JUCE_API FileChooser { public: - /** Creates a hover detector. + /** Creates a FileChooser. - Initially the object is inactive, and you need to tell it which component - to monitor, using the setHoverComponent() method. + After creating one of these, use one of the browseFor... methods to display it. - @param hoverTimeMillisecs the number of milliseconds for which the mouse - needs to stay still before the mouseHovered() method - is invoked. You can change this setting later with - the setHoverTimeMillisecs() method + @param dialogBoxTitle a text string to display in the dialog box to + tell the user what's going on + @param initialFileOrDirectory the file or directory that should be selected when + the dialog box opens. If this parameter is set to + File::nonexistent, a sensible default directory + will be used instead. + @param filePatternsAllowed a set of file patterns to specify which files can be + selected - each pattern should be separated by a + comma or semi-colon, e.g. "*" or "*.jpg;*.gif". An + empty string means that all files are allowed + @param useOSNativeDialogBox if true, then a native dialog box will be used if + possible; if false, then a Juce-based browser dialog + box will always be used + @see browseForFileToOpen, browseForFileToSave, browseForDirectory */ - MouseHoverDetector (const int hoverTimeMillisecs = 400); + FileChooser (const String& dialogBoxTitle, + const File& initialFileOrDirectory = File::nonexistent, + const String& filePatternsAllowed = String::empty, + const bool useOSNativeDialogBox = true); /** Destructor. */ - virtual ~MouseHoverDetector(); + ~FileChooser(); - /** Changes the time for which the mouse has to stay still before it's considered - to be hovering. + /** Shows a dialog box to choose a file to open. + + This will display the dialog box modally, using an "open file" mode, so that + it won't allow non-existent files or directories to be chosen. + + @param previewComponent an optional component to display inside the dialog + box to show special info about the files that the user + is browsing. The component will not be deleted by this + object, so the caller must take care of it. + @returns true if the user selected a file, in which case, use the getResult() + method to find out what it was. Returns false if they cancelled instead. + @see browseForFileToSave, browseForDirectory */ - void setHoverTimeMillisecs (const int newTimeInMillisecs); + bool browseForFileToOpen (FilePreviewComponent* previewComponent = 0); - /** Changes the component that's being monitored for hovering. + /** Same as browseForFileToOpen, but allows the user to select multiple files. - Be careful not to delete a component that's being monitored without first - stopping or deleting the hover detector. + The files that are returned can be obtained by calling getResults(). See + browseForFileToOpen() for more info about the behaviour of this method. */ - void setHoverComponent (Component* const newSourceComponent); + bool browseForMultipleFilesToOpen (FilePreviewComponent* previewComponent = 0); -protected: + /** Shows a dialog box to choose a file to save. - /** Called back when the mouse hovers. + This will display the dialog box modally, using an "save file" mode, so it + will allow non-existent files to be chosen, but not directories. - After the mouse has stayed still over the component for the length of time - specified by setHoverTimeMillisecs(), this method will be invoked. + @param warnAboutOverwritingExistingFiles if true, the dialog box will ask + the user if they're sure they want to overwrite a file that already + exists + @returns true if the user chose a file and pressed 'ok', in which case, use + the getResult() method to find out what the file was. Returns false + if they cancelled instead. + @see browseForFileToOpen, browseForDirectory + */ + bool browseForFileToSave (const bool warnAboutOverwritingExistingFiles); - When the mouse is first moved after this callback has occurred, the - mouseMovedAfterHover() method will be called. + /** Shows a dialog box to choose a directory. - @param mouseX the mouse's X position relative to the component being monitored - @param mouseY the mouse's Y position relative to the component being monitored + This will display the dialog box modally, using an "open directory" mode, so it + will only allow directories to be returned, not files. + + @returns true if the user chose a directory and pressed 'ok', in which case, use + the getResult() method to find out what they chose. Returns false + if they cancelled instead. + @see browseForFileToOpen, browseForFileToSave */ - virtual void mouseHovered (int mouseX, - int mouseY) = 0; + bool browseForDirectory(); - /** Called when the mouse is moved away after just having hovered. */ - virtual void mouseMovedAfterHover() = 0; + /** Same as browseForFileToOpen, but allows the user to select multiple files and directories. -private: + The files that are returned can be obtained by calling getResults(). See + browseForFileToOpen() for more info about the behaviour of this method. + */ + bool browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComponent = 0); - class JUCE_API HoverDetectorInternal : public MouseListener, - public Timer - { - public: - MouseHoverDetector* owner; - int lastX, lastY; + /** Returns the last file that was chosen by one of the browseFor methods. - void timerCallback(); - void mouseEnter (const MouseEvent&); - void mouseExit (const MouseEvent&); - void mouseDown (const MouseEvent&); - void mouseUp (const MouseEvent&); - void mouseMove (const MouseEvent&); - void mouseWheelMove (const MouseEvent&, float, float); + After calling the appropriate browseFor... method, this method lets you + find out what file or directory they chose. - } internalTimer; + Note that the file returned is only valid if the browse method returned true (i.e. + if the user pressed 'ok' rather than cancelling). - friend class HoverDetectorInternal; + If you're using a multiple-file select, then use the getResults() method instead, + to obtain the list of all files chosen. - Component* source; - int hoverTimeMillisecs; - bool hasJustHovered; + @see getResults + */ + const File getResult() const; - void hoverTimerCallback(); - void checkJustHoveredCallback(); -}; + /** Returns a list of all the files that were chosen during the last call to a + browse method. -#endif // __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ -/********* End of inlined file: juce_MouseHoverDetector.h *********/ + This array may be empty if no files were chosen, or can contain multiple entries + if multiple files were chosen. -#endif -#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__ + @see getResult + */ + const OwnedArray & getResults() const; -#endif -#ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ + juce_UseDebuggingNewOperator -#endif -#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ +private: + String title, filters; + File startingFile; + OwnedArray results; + bool useNativeDialogBox; -#endif -#ifndef __JUCE_COMBOBOX_JUCEHEADER__ + bool showDialog (const bool selectsDirectories, + const bool selectsFiles, + const bool isSave, + const bool warnAboutOverwritingExistingFiles, + const bool selectMultipleFiles, + FilePreviewComponent* const previewComponent); -#endif -#ifndef __JUCE_LABEL_JUCEHEADER__ + static void showPlatformDialog (OwnedArray& results, + const String& title, + const File& file, + const String& filters, + bool selectsDirectories, + bool selectsFiles, + bool isSave, + bool warnAboutOverwritingExistingFiles, + bool selectMultipleFiles, + FilePreviewComponent* previewComponent); +}; + +#endif // __JUCE_FILECHOOSER_JUCEHEADER__ +/********* End of inlined file: juce_FileChooser.h *********/ #endif -#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ +#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ -/********* Start of inlined file: juce_ProgressBar.h *********/ -#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ -#define __JUCE_PROGRESSBAR_JUCEHEADER__ +/********* Start of inlined file: juce_FileChooserDialogBox.h *********/ +#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ +#define __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ -/** - A progress bar component. +/********* Start of inlined file: juce_ResizableWindow.h *********/ +#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__ +#define __JUCE_RESIZABLEWINDOW_JUCEHEADER__ - To use this, just create one and make it visible. It'll run its own timer - to keep an eye on a variable that you give it, and will automatically - redraw itself when the variable changes. +/********* Start of inlined file: juce_TopLevelWindow.h *********/ +#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__ +#define __JUCE_TOPLEVELWINDOW_JUCEHEADER__ - For an easy way of running a background task with a dialog box showing its - progress, see the ThreadWithProgressWindow class. +/********* Start of inlined file: juce_DropShadower.h *********/ +#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ +#define __JUCE_DROPSHADOWER_JUCEHEADER__ - @see ThreadWithProgressWindow +/** + Adds a drop-shadow to a component. + + This object creates and manages a set of components which sit around a + component, creating a gaussian shadow around it. The components will track + the position of the component and if it's brought to the front they'll also + follow this. + + For desktop windows you don't need to use this class directly - just + set the Component::windowHasDropShadow flag when calling + Component::addToDesktop(), and the system will create one of these if it's + needed (which it obviously isn't on the Mac, for example). */ -class JUCE_API ProgressBar : public Component, - public SettableTooltipClient, - private Timer +class JUCE_API DropShadower : public ComponentListener { public: - /** Creates a ProgressBar. + /** Creates a DropShadower. - @param progress pass in a reference to a double that you're going to - update with your task's progress. The ProgressBar will - monitor the value of this variable and will redraw itself - when the value changes. The range is from 0 to 1.0. Obviously - you'd better be careful not to delete this variable while the - ProgressBar still exists! + @param alpha the opacity of the shadows, from 0 to 1.0 + @param xOffset the horizontal displacement of the shadow, in pixels + @param yOffset the vertical displacement of the shadow, in pixels + @param blurRadius the radius of the blur to use for creating the shadow */ - ProgressBar (double& progress); + DropShadower (const float alpha = 0.5f, + const int xOffset = 1, + const int yOffset = 5, + const float blurRadius = 10.0f); /** Destructor. */ - ~ProgressBar(); + virtual ~DropShadower(); - /** Turns the percentage display on or off. + /** Attaches the DropShadower to the component you want to shadow. */ + void setOwner (Component* componentToFollow); - By default this is on, and the progress bar will display a text string showing - its current percentage. - */ - void setPercentageDisplay (const bool shouldDisplayPercentage); + /** @internal */ + void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); + /** @internal */ + void componentBroughtToFront (Component& component); + /** @internal */ + void componentChildrenChanged (Component& component); + /** @internal */ + void componentParentHierarchyChanged (Component& component); + /** @internal */ + void componentVisibilityChanged (Component& component); - /** Gives the progress bar a string to display inside it. + juce_UseDebuggingNewOperator - If you call this, it will turn off the percentage display. - @see setPercentageDisplay - */ - void setTextToDisplay (const String& text); +private: - /** A set of colour IDs to use to change the colour of various aspects of the bar. + Component* owner; + int numShadows; + Component* shadowWindows[4]; + Image* shadowImageSections[12]; + const int shadowEdge, xOffset, yOffset; + const float alpha, blurRadius; + bool inDestructor, reentrant; - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + void updateShadows(); + void setShadowImage (Image* const src, + const int num, + const int w, const int h, + const int sx, const int sy) throw(); - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - backgroundColourId = 0x1001900, /**< The background colour, behind the bar. */ - foregroundColourId = 0x1001a00, /**< The colour to use to draw the bar itself. LookAndFeel - classes will probably use variations on this colour. */ - }; - - juce_UseDebuggingNewOperator - -protected: - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - void visibilityChanged(); - /** @internal */ - void colourChanged(); - -private: - double& progress; - double currentValue; - bool displayPercentage; - String displayedMessage, currentMessage; - uint32 lastCallbackTime; - - void timerCallback(); + void bringShadowWindowsToFront(); + void deleteShadowWindows(); - ProgressBar (const ProgressBar&); - const ProgressBar& operator= (const ProgressBar&); + DropShadower (const DropShadower&); + const DropShadower& operator= (const DropShadower&); }; -#endif // __JUCE_PROGRESSBAR_JUCEHEADER__ -/********* End of inlined file: juce_ProgressBar.h *********/ - -#endif -#ifndef __JUCE_SLIDER_JUCEHEADER__ +#endif // __JUCE_DROPSHADOWER_JUCEHEADER__ +/********* End of inlined file: juce_DropShadower.h *********/ -/********* Start of inlined file: juce_Slider.h *********/ -#ifndef __JUCE_SLIDER_JUCEHEADER__ -#define __JUCE_SLIDER_JUCEHEADER__ +/** + A base class for top-level windows. -/********* Start of inlined file: juce_SliderListener.h *********/ -#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ -#define __JUCE_SLIDERLISTENER_JUCEHEADER__ + This class is used for components that are considered a major part of your + application - e.g. ResizableWindow, DocumentWindow, DialogWindow, AlertWindow, + etc. Things like menus that pop up briefly aren't derived from it. -class Slider; + A TopLevelWindow is probably on the desktop, but this isn't mandatory - it + could itself be the child of another component. -/** - A class for receiving callbacks from a Slider. + The class manages a list of all instances of top-level windows that are in use, + and each one is also given the concept of being "active". The active window is + one that is actively being used by the user. This isn't quite the same as the + component with the keyboard focus, because there may be a popup menu or other + temporary window which gets keyboard focus while the active top level window is + unchanged. - To be told when a slider's value changes, you can register a SliderListener - object using Slider::addListener(). + A top-level window also has an optional drop-shadow. - @see Slider::addListener, Slider::removeListener + @see ResizableWindow, DocumentWindow, DialogWindow */ -class JUCE_API SliderListener +class JUCE_API TopLevelWindow : public Component { public: - /** Destructor. */ - virtual ~SliderListener() {} - - /** Called when the slider's value is changed. - - This may be caused by dragging it, or by typing in its text entry box, - or by a call to Slider::setValue(). - - You can find out the new value using Slider::getValue(). + /** Creates a TopLevelWindow. - @see Slider::valueChanged + @param name the name to give the component + @param addToDesktop if true, the window will be automatically added to the + desktop; if false, you can use it as a child component */ - virtual void sliderValueChanged (Slider* slider) = 0; - - /** Called when the slider is about to be dragged. + TopLevelWindow (const String& name, + const bool addToDesktop); - This is called when a drag begins, then it's followed by multiple calls - to sliderValueChanged(), and then sliderDragEnded() is called after the - user lets go. + /** Destructor. */ + ~TopLevelWindow(); - @see sliderDragEnded, Slider::startedDragging - */ - virtual void sliderDragStarted (Slider* slider); + /** True if this is currently the TopLevelWindow that is actively being used. - /** Called after a drag operation has finished. + This isn't quite the same as having keyboard focus, because the focus may be + on a child component or a temporary pop-up menu, etc, while this window is + still considered to be active. - @see sliderDragStarted, Slider::stoppedDragging + @see activeWindowStatusChanged */ - virtual void sliderDragEnded (Slider* slider); -}; - -#endif // __JUCE_SLIDERLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_SliderListener.h *********/ - -/** - A slider control for changing a value. - - The slider can be horizontal, vertical, or rotary, and can optionally have - a text-box inside it to show an editable display of the current value. - - To use it, create a Slider object and use the setSliderStyle() method - to set up the type you want. To set up the text-entry box, use setTextBoxStyle(). + bool isActiveWindow() const throw() { return windowIsActive_; } - To define the values that it can be set to, see the setRange() and setValue() methods. + /** This will set the bounds of the window so that it's centred in front of another + window. - There are also lots of custom tweaks you can do by subclassing and overriding - some of the virtual methods, such as changing the scaling, changing the format of - the text display, custom ways of limiting the values, etc. + If your app has a few windows open and want to pop up a dialog box for one of + them, you can use this to show it in front of the relevent parent window, which + is a bit neater than just having it appear in the middle of the screen. - You can register SliderListeners with a slider, which will be informed when the value - changes, or a subclass can override valueChanged() to be informed synchronously. + If componentToCentreAround is 0, then the currently active TopLevelWindow will + be used instead. If no window is focused, it'll just default to the middle of the + screen. + */ + void centreAroundComponent (Component* componentToCentreAround, + const int width, const int height); - @see SliderListener -*/ -class JUCE_API Slider : public Component, - public SettableTooltipClient, - private AsyncUpdater, - private ButtonListener, - private LabelListener -{ -public: + /** Turns the drop-shadow on and off. */ + void setDropShadowEnabled (const bool useShadow); - /** Creates a slider. + /** Sets whether an OS-native title bar will be used, or a Juce one. - When created, you'll need to set up the slider's style and range with setSliderStyle(), - setRange(), etc. + @see isUsingNativeTitleBar */ - Slider (const String& componentName); - - /** Destructor. */ - ~Slider(); + void setUsingNativeTitleBar (const bool useNativeTitleBar); - /** The types of slider available. + /** Returns true if the window is currently using an OS-native title bar. - @see setSliderStyle, setRotaryParameters + @see setUsingNativeTitleBar */ - enum SliderStyle - { - LinearHorizontal, /**< A traditional horizontal slider. */ - LinearVertical, /**< A traditional vertical slider. */ - LinearBar, /**< A horizontal bar slider with the text label drawn on top of it. */ - Rotary, /**< A rotary control that you move by dragging the mouse in a circular motion, like a knob. - @see setRotaryParameters */ - RotaryHorizontalDrag, /**< A rotary control that you move by dragging the mouse left-to-right. - @see setRotaryParameters */ - RotaryVerticalDrag, /**< A rotary control that you move by dragging the mouse up-and-down. - @see setRotaryParameters */ - IncDecButtons, /**< A pair of buttons that increment or decrement the slider's value by the increment set in setRange(). */ + bool isUsingNativeTitleBar() const throw() { return useNativeTitleBar && isOnDesktop(); } - TwoValueHorizontal, /**< A horizontal slider that has two thumbs instead of one, so it can show a minimum and maximum value. - @see setMinValue, setMaxValue */ - TwoValueVertical, /**< A vertical slider that has two thumbs instead of one, so it can show a minimum and maximum value. - @see setMinValue, setMaxValue */ + /** Returns the number of TopLevelWindow objects currently in use. - ThreeValueHorizontal, /**< A horizontal slider that has three thumbs instead of one, so it can show a minimum and maximum - value, with the current value being somewhere between them. - @see setMinValue, setMaxValue */ - ThreeValueVertical, /**< A vertical slider that has three thumbs instead of one, so it can show a minimum and maximum - value, with the current value being somewhere between them. - @see setMinValue, setMaxValue */ - }; + @see getTopLevelWindow + */ + static int getNumTopLevelWindows() throw(); - /** Changes the type of slider interface being used. + /** Returns one of the TopLevelWindow objects currently in use. - @param newStyle the type of interface - @see setRotaryParameters, setVelocityBasedMode, + The index is 0 to (getNumTopLevelWindows() - 1). */ - void setSliderStyle (const SliderStyle newStyle); + static TopLevelWindow* getTopLevelWindow (const int index) throw(); - /** Returns the slider's current style. + /** Returns the currently-active top level window. - @see setSliderStyle + There might not be one, of course, so this can return 0. */ - SliderStyle getSliderStyle() const throw() { return style; } + static TopLevelWindow* getActiveTopLevelWindow() throw(); - /** Changes the properties of a rotary slider. + juce_UseDebuggingNewOperator - @param startAngleRadians the angle (in radians, clockwise from the top) at which - the slider's minimum value is represented - @param endAngleRadians the angle (in radians, clockwise from the top) at which - the slider's maximum value is represented. This must be - greater than startAngleRadians - @param stopAtEnd if true, then when the slider is dragged around past the - minimum or maximum, it'll stop there; if false, it'll wrap - back to the opposite value - */ - void setRotaryParameters (const float startAngleRadians, - const float endAngleRadians, - const bool stopAtEnd); + /** @internal */ + virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = 0); - /** Sets the distance the mouse has to move to drag the slider across - the full extent of its range. +protected: - This only applies when in modes like RotaryHorizontalDrag, where it's using - relative mouse movements to adjust the slider. + /** This callback happens when this window becomes active or inactive. + + @see isActiveWindow */ - void setMouseDragSensitivity (const int distanceForFullScaleDrag); + virtual void activeWindowStatusChanged(); - /** Changes the way the the mouse is used when dragging the slider. + /** @internal */ + void focusOfChildComponentChanged (FocusChangeType cause); + /** @internal */ + void parentHierarchyChanged(); + /** @internal */ + void visibilityChanged(); + /** @internal */ + virtual int getDesktopWindowStyleFlags() const; + /** @internal */ + void recreateDesktopWindow(); - If true, this will turn on velocity-sensitive dragging, so that - the faster the mouse moves, the bigger the movement to the slider. This - helps when making accurate adjustments if the slider's range is quite large. +private: + friend class TopLevelWindowManager; + bool useDropShadow, useNativeTitleBar, windowIsActive_; + DropShadower* shadower; - If false, the slider will just try to snap to wherever the mouse is. - */ - void setVelocityBasedMode (const bool isVelocityBased) throw(); + void setWindowActive (const bool isNowActive) throw(); - /** Returns true if velocity-based mode is active. - @see setVelocityBasedMode - */ - bool getVelocityBasedMode() const throw() { return isVelocityBased; } + TopLevelWindow (const TopLevelWindow&); + const TopLevelWindow& operator= (const TopLevelWindow&); +}; - /** Changes aspects of the scaling used when in velocity-sensitive mode. +#endif // __JUCE_TOPLEVELWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_TopLevelWindow.h *********/ - These apply when you've used setVelocityBasedMode() to turn on velocity mode, - or if you're holding down ctrl. +/********* Start of inlined file: juce_ComponentDragger.h *********/ +#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__ +#define __JUCE_COMPONENTDRAGGER_JUCEHEADER__ - @param sensitivity higher values than 1.0 increase the range of acceleration used - @param threshold the minimum number of pixels that the mouse needs to move for it - to be treated as a movement - @param offset values greater than 0.0 increase the minimum speed that will be used when - the threshold is reached - @param userCanPressKeyToSwapMode if true, then the user can hold down the ctrl or command - key to toggle velocity-sensitive mode - */ - void setVelocityModeParameters (const double sensitivity = 1.0, - const int threshold = 1, - const double offset = 0.0, - const bool userCanPressKeyToSwapMode = true) throw(); +/********* Start of inlined file: juce_ComponentBoundsConstrainer.h *********/ +#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ +#define __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ - /** Returns the velocity sensitivity setting. - @see setVelocityModeParameters - */ - double getVelocitySensitivity() const throw() { return velocityModeSensitivity; } +/** + A class that imposes restrictions on a Component's size or position. - /** Returns the velocity threshold setting. - @see setVelocityModeParameters - */ - int getVelocityThreshold() const throw() { return velocityModeThreshold; } + This is used by classes such as ResizableCornerComponent, + ResizableBorderComponent and ResizableWindow. - /** Returns the velocity offset setting. - @see setVelocityModeParameters - */ - double getVelocityOffset() const throw() { return velocityModeOffset; } + The base class can impose some basic size and position limits, but you can + also subclass this for custom uses. - /** Returns the velocity user key setting. - @see setVelocityModeParameters - */ - bool getVelocityModeIsSwappable() const throw() { return userKeyOverridesVelocity; } + @see ResizableCornerComponent, ResizableBorderComponent, ResizableWindow +*/ +class JUCE_API ComponentBoundsConstrainer +{ +public: - /** Sets up a skew factor to alter the way values are distributed. + /** When first created, the object will not impose any restrictions on the components. */ + ComponentBoundsConstrainer() throw(); - You may want to use a range of values on the slider where more accuracy - is required towards one end of the range, so this will logarithmically - spread the values across the length of the slider. + /** Destructor. */ + virtual ~ComponentBoundsConstrainer(); - If the factor is < 1.0, the lower end of the range will fill more of the - slider's length; if the factor is > 1.0, the upper end of the range - will be expanded instead. A factor of 1.0 doesn't skew it at all. + /** Imposes a minimum width limit. */ + void setMinimumWidth (const int minimumWidth) throw(); - To set the skew position by using a mid-point, use the setSkewFactorFromMidPoint() - method instead. + /** Returns the current minimum width. */ + int getMinimumWidth() const throw() { return minW; } - @see getSkewFactor, setSkewFactorFromMidPoint - */ - void setSkewFactor (const double factor) throw(); + /** Imposes a maximum width limit. */ + void setMaximumWidth (const int maximumWidth) throw(); - /** Sets up a skew factor to alter the way values are distributed. + /** Returns the current maximum width. */ + int getMaximumWidth() const throw() { return maxW; } - This allows you to specify the slider value that should appear in the - centre of the slider's visible range. + /** Imposes a minimum height limit. */ + void setMinimumHeight (const int minimumHeight) throw(); - @see setSkewFactor, getSkewFactor - */ - void setSkewFactorFromMidPoint (const double sliderValueToShowAtMidPoint) throw(); + /** Returns the current minimum height. */ + int getMinimumHeight() const throw() { return minH; } - /** Returns the current skew factor. + /** Imposes a maximum height limit. */ + void setMaximumHeight (const int maximumHeight) throw(); - See setSkewFactor for more info. + /** Returns the current maximum height. */ + int getMaximumHeight() const throw() { return maxH; } - @see setSkewFactor, setSkewFactorFromMidPoint - */ - double getSkewFactor() const throw() { return skewFactor; } + /** Imposes a minimum width and height limit. */ + void setMinimumSize (const int minimumWidth, + const int minimumHeight) throw(); - /** Used by setIncDecButtonsMode(). - */ - enum IncDecButtonMode - { - incDecButtonsNotDraggable, - incDecButtonsDraggable_AutoDirection, - incDecButtonsDraggable_Horizontal, - incDecButtonsDraggable_Vertical - }; + /** Imposes a maximum width and height limit. */ + void setMaximumSize (const int maximumWidth, + const int maximumHeight) throw(); - /** When the style is IncDecButtons, this lets you turn on a mode where the mouse - can be dragged on the buttons to drag the values. + /** Set all the maximum and minimum dimensions. */ + void setSizeLimits (const int minimumWidth, + const int minimumHeight, + const int maximumWidth, + const int maximumHeight) throw(); - By default this is turned off. When enabled, clicking on the buttons still works - them as normal, but by holding down the mouse on a button and dragging it a little - distance, it flips into a mode where the value can be dragged. The drag direction can - either be set explicitly to be vertical or horizontal, or can be set to - incDecButtonsDraggable_AutoDirection so that it depends on whether the buttons - are side-by-side or above each other. - */ - void setIncDecButtonsMode (const IncDecButtonMode mode); + /** Sets the amount by which the component is allowed to go off-screen. - /** The position of the slider's text-entry box. + The values indicate how many pixels must remain on-screen when dragged off + one of its parent's edges, so e.g. if minimumWhenOffTheTop is set to 10, then + when the component goes off the top of the screen, its y-position will be + clipped so that there are always at least 10 pixels on-screen. In other words, + the lowest y-position it can take would be (10 - the component's height). - @see setTextBoxStyle + If you pass 0 or less for one of these amounts, the component is allowed + to move beyond that edge completely, with no restrictions at all. + + If you pass a very large number (i.e. larger that the dimensions of the + component itself), then the component won't be allowed to overlap that + edge at all. So e.g. setting minimumWhenOffTheLeft to 0xffffff will mean that + the component will bump into the left side of the screen and go no further. */ - enum TextEntryBoxPosition - { - NoTextBox, /**< Doesn't display a text box. */ - TextBoxLeft, /**< Puts the text box to the left of the slider, vertically centred. */ - TextBoxRight, /**< Puts the text box to the right of the slider, vertically centred. */ - TextBoxAbove, /**< Puts the text box above the slider, horizontally centred. */ - TextBoxBelow /**< Puts the text box below the slider, horizontally centred. */ - }; + void setMinimumOnscreenAmounts (const int minimumWhenOffTheTop, + const int minimumWhenOffTheLeft, + const int minimumWhenOffTheBottom, + const int minimumWhenOffTheRight) throw(); - /** Changes the location and properties of the text-entry box. + /** Specifies a width-to-height ratio that the resizer should always maintain. - @param newPosition where it should go (or NoTextBox to not have one at all) - @param isReadOnly if true, it's a read-only display - @param textEntryBoxWidth the width of the text-box in pixels. Make sure this leaves enough - room for the slider as well! - @param textEntryBoxHeight the height of the text-box in pixels. Make sure this leaves enough - room for the slider as well! + If the value is 0, no aspect ratio is enforced. If it's non-zero, the width + will always be maintained as this multiple of the height. - @see setTextBoxIsEditable, getValueFromText, getTextFromValue + @see setResizeLimits */ - void setTextBoxStyle (const TextEntryBoxPosition newPosition, - const bool isReadOnly, - const int textEntryBoxWidth, - const int textEntryBoxHeight); + void setFixedAspectRatio (const double widthOverHeight) throw(); - /** Returns the status of the text-box. - @see setTextBoxStyle - */ - const TextEntryBoxPosition getTextBoxPosition() const throw() { return textBoxPos; } + /** Returns the aspect ratio that was set with setFixedAspectRatio(). - /** Returns the width used for the text-box. - @see setTextBoxStyle + If no aspect ratio is being enforced, this will return 0. */ - int getTextBoxWidth() const throw() { return textBoxWidth; } + double getFixedAspectRatio() const throw(); - /** Returns the height used for the text-box. - @see setTextBoxStyle + /** This callback changes the given co-ordinates to impose whatever the current + constraints are set to be. + + @param x the x position that should be examined and adjusted + @param y the y position that should be examined and adjusted + @param w the width that should be examined and adjusted + @param h the height that should be examined and adjusted + @param previousBounds the component's current size + @param limits the region in which the component can be positioned + @param isStretchingTop whether the top edge of the component is being resized + @param isStretchingLeft whether the left edge of the component is being resized + @param isStretchingBottom whether the bottom edge of the component is being resized + @param isStretchingRight whether the right edge of the component is being resized */ - int getTextBoxHeight() const throw() { return textBoxHeight; } + virtual void checkBounds (int& x, int& y, int& w, int& h, + const Rectangle& previousBounds, + const Rectangle& limits, + const bool isStretchingTop, + const bool isStretchingLeft, + const bool isStretchingBottom, + const bool isStretchingRight); - /** Makes the text-box editable. + /** This callback happens when the resizer is about to start dragging. */ + virtual void resizeStart(); - By default this is true, and the user can enter values into the textbox, - but it can be turned off if that's not suitable. + /** This callback happens when the resizer has finished dragging. */ + virtual void resizeEnd(); - @see setTextBoxStyle, getValueFromText, getTextFromValue - */ - void setTextBoxIsEditable (const bool shouldBeEditable) throw(); + /** Checks the given bounds, and then sets the component to the corrected size. */ + void setBoundsForComponent (Component* const component, + int x, int y, int w, int h, + const bool isStretchingTop, + const bool isStretchingLeft, + const bool isStretchingBottom, + const bool isStretchingRight); - /** Returns true if the text-box is read-only. - @see setTextBoxStyle + /** Performs a check on the current size of a component, and moves or resizes + it if it fails the constraints. */ - bool isTextBoxEditable() const throw() { return editableText; } + void checkComponentBounds (Component* component); - /** If the text-box is editable, this will give it the focus so that the user can - type directly into it. + /** Called by setBoundsForComponent() to apply a new constrained size to a + component. - This is basically the effect as the user clicking on it. + By default this just calls setBounds(), but it virtual in case it's needed for + extremely cunning purposes. */ - void showTextBox(); + virtual void applyBoundsToComponent (Component* component, + int x, int y, int w, int h); - /** If the text-box currently has focus and is being edited, this resets it and takes keyboard - focus away from it. + juce_UseDebuggingNewOperator - @param discardCurrentEditorContents if true, the slider's value will be left - unchanged; if false, the current contents of the - text editor will be used to set the slider position - before it is hidden. - */ - void hideTextBox (const bool discardCurrentEditorContents); +private: + int minW, maxW, minH, maxH; + int minOffTop, minOffLeft, minOffBottom, minOffRight; + double aspectRatio; - /** Changes the slider's current value. + ComponentBoundsConstrainer (const ComponentBoundsConstrainer&); + const ComponentBoundsConstrainer& operator= (const ComponentBoundsConstrainer&); +}; - This will trigger a callback to SliderListener::sliderValueChanged() for any listeners - that are registered, and will synchronously call the valueChanged() method in case subclasses - want to handle it. +#endif // __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ +/********* End of inlined file: juce_ComponentBoundsConstrainer.h *********/ - @param newValue the new value to set - this will be restricted by the - minimum and maximum range, and will be snapped to the - nearest interval if one has been set - @param sendUpdateMessage if false, a change to the value will not trigger a call to - any SliderListeners or the valueChanged() method - @param sendMessageSynchronously if true, then a call to the SliderListeners will be made - synchronously; if false, it will be asynchronous - */ - void setValue (double newValue, - const bool sendUpdateMessage = true, - const bool sendMessageSynchronously = false); +/** + An object to take care of the logic for dragging components around with the mouse. - /** Returns the slider's current value. */ - double getValue() const throw(); + Very easy to use - in your mouseDown() callback, call startDraggingComponent(), + then in your mouseDrag() callback, call dragComponent(). - /** Sets the limits that the slider's value can take. + When starting a drag, you can give it a ComponentBoundsConstrainer to use + to limit the component's position and keep it on-screen. - @param newMinimum the lowest value allowed - @param newMaximum the highest value allowed - @param newInterval the steps in which the value is allowed to increase - if this - is not zero, the value will always be (newMinimum + (newInterval * an integer)). - */ - void setRange (const double newMinimum, - const double newMaximum, - const double newInterval = 0); + e.g. @code + class MyDraggableComp + { + ComponentDragger myDragger; - /** Returns the current maximum value. - @see setRange - */ - double getMaximum() const throw() { return maximum; } + void mouseDown (const MouseEvent& e) + { + myDragger.startDraggingComponent (this, 0); + } - /** Returns the current minimum value. - @see setRange - */ - double getMinimum() const throw() { return minimum; } + void mouseDrag (const MouseEvent& e) + { + myDragger.dragComponent (this, e); + } + }; + @endcode +*/ +class JUCE_API ComponentDragger +{ +public: - /** Returns the current step-size for values. - @see setRange - */ - double getInterval() const throw() { return interval; } + /** Creates a ComponentDragger. */ + ComponentDragger(); - /** For a slider with two or three thumbs, this returns the lower of its values. + /** Destructor. */ + virtual ~ComponentDragger(); - For a two-value slider, the values are controlled with getMinValue() and getMaxValue(). - A slider with three values also uses the normal getValue() and setValue() methods to - control the middle value. + /** Call this from your component's mouseDown() method, to prepare for dragging. - @see setMinValue, getMaxValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical + @param componentToDrag the component that you want to drag + @param constrainer a constrainer object to use to keep the component + from going offscreen + @see dragComponent */ - double getMinValue() const throw(); + void startDraggingComponent (Component* const componentToDrag, + ComponentBoundsConstrainer* constrainer); - /** For a slider with two or three thumbs, this sets the lower of its values. + /** Call this from your mouseDrag() callback to move the component. - This will trigger a callback to SliderListener::sliderValueChanged() for any listeners - that are registered, and will synchronously call the valueChanged() method in case subclasses - want to handle it. + This will move the component, but will first check the validity of the + component's new position using the checkPosition() method, which you + can override if you need to enforce special positioning limits on the + component. - @param newValue the new value to set - this will be restricted by the - minimum and maximum range, and will be snapped to the nearest - interval if one has been set. - @param sendUpdateMessage if false, a change to the value will not trigger a call to - any SliderListeners or the valueChanged() method - @param sendMessageSynchronously if true, then a call to the SliderListeners will be made - synchronously; if false, it will be asynchronous - @param allowNudgingOfOtherValues if false, this value will be restricted to being below the - max value (in a two-value slider) or the mid value (in a three-value - slider). If false, then if this value goes beyond those values, - it will push them along with it. - @see getMinValue, setMaxValue, setValue + @param componentToDrag the component that you want to drag + @param e the current mouse-drag event + @see dragComponent */ - void setMinValue (double newValue, - const bool sendUpdateMessage = true, - const bool sendMessageSynchronously = false, - const bool allowNudgingOfOtherValues = false); + void dragComponent (Component* const componentToDrag, + const MouseEvent& e); - /** For a slider with two or three thumbs, this returns the higher of its values. + juce_UseDebuggingNewOperator - For a two-value slider, the values are controlled with getMinValue() and getMaxValue(). - A slider with three values also uses the normal getValue() and setValue() methods to - control the middle value. +private: + ComponentBoundsConstrainer* constrainer; + int originalX, originalY; +}; - @see getMinValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical - */ - double getMaxValue() const throw(); +#endif // __JUCE_COMPONENTDRAGGER_JUCEHEADER__ +/********* End of inlined file: juce_ComponentDragger.h *********/ - /** For a slider with two or three thumbs, this sets the lower of its values. +/********* Start of inlined file: juce_ResizableBorderComponent.h *********/ +#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ +#define __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ - This will trigger a callback to SliderListener::sliderValueChanged() for any listeners - that are registered, and will synchronously call the valueChanged() method in case subclasses - want to handle it. +/** + A component that resizes its parent window when dragged. - @param newValue the new value to set - this will be restricted by the - minimum and maximum range, and will be snapped to the nearest - interval if one has been set. - @param sendUpdateMessage if false, a change to the value will not trigger a call to - any SliderListeners or the valueChanged() method - @param sendMessageSynchronously if true, then a call to the SliderListeners will be made - synchronously; if false, it will be asynchronous - @param allowNudgingOfOtherValues if false, this value will be restricted to being above the - min value (in a two-value slider) or the mid value (in a three-value - slider). If false, then if this value goes beyond those values, - it will push them along with it. - @see getMaxValue, setMinValue, setValue - */ - void setMaxValue (double newValue, - const bool sendUpdateMessage = true, - const bool sendMessageSynchronously = false, - const bool allowNudgingOfOtherValues = false); + This component forms a frame around the edge of a component, allowing it to + be dragged by the edges or corners to resize it - like the way windows are + resized in MSWindows or Linux. - /** Adds a listener to be called when this slider's value changes. */ - void addListener (SliderListener* const listener) throw(); + To use it, just add it to your component, making it fill the entire parent component + (there's a mouse hit-test that only traps mouse-events which land around the + edge of the component, so it's even ok to put it on top of any other components + you're using). Make sure you rescale the resizer component to fill the parent + each time the parent's size changes. - /** Removes a previously-registered listener. */ - void removeListener (SliderListener* const listener) throw(); + @see ResizableCornerComponent +*/ +class JUCE_API ResizableBorderComponent : public Component +{ +public: - /** This lets you choose whether double-clicking moves the slider to a given position. + /** Creates a resizer. - By default this is turned off, but it's handy if you want a double-click to act - as a quick way of resetting a slider. Just pass in the value you want it to - go to when double-clicked. + Pass in the target component which you want to be resized when this one is + dragged. - @see getDoubleClickReturnValue + The target component will usually be a parent of the resizer component, but this + isn't mandatory. + + Remember that when the target component is resized, it'll need to move and + resize this component to keep it in place, as this won't happen automatically. + + If the constrainer parameter is non-zero, then this object will be used to enforce + limits on the size and position that the component can be stretched to. Make sure + that the constrainer isn't deleted while still in use by this object. + + @see ComponentBoundsConstrainer */ - void setDoubleClickReturnValue (const bool isDoubleClickEnabled, - const double valueToSetOnDoubleClick) throw(); + ResizableBorderComponent (Component* const componentToResize, + ComponentBoundsConstrainer* const constrainer); - /** Returns the values last set by setDoubleClickReturnValue() method. + /** Destructor. */ + ~ResizableBorderComponent(); - Sets isEnabled to true if double-click is enabled, and returns the value - that was set. + /** Specifies how many pixels wide the draggable edges of this component are. - @see setDoubleClickReturnValue + @see getBorderThickness */ - double getDoubleClickReturnValue (bool& isEnabled) const throw(); + void setBorderThickness (const BorderSize& newBorderSize) throw(); - /** Tells the slider whether to keep sending change messages while the user - is dragging the slider. + /** Returns the number of pixels wide that the draggable edges of this component are. - If set to true, a change message will only be sent when the user has - dragged the slider and let go. If set to false (the default), then messages - will be continuously sent as they drag it while the mouse button is still - held down. + @see setBorderThickness */ - void setChangeNotificationOnlyOnRelease (const bool onlyNotifyOnRelease) throw(); + const BorderSize getBorderThickness() const throw(); - /** This lets you change whether the slider thumb jumps to the mouse position - when you click. + juce_UseDebuggingNewOperator - By default, this is true. If it's false, then the slider moves with relative - motion when you drag it. +protected: + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void mouseEnter (const MouseEvent& e); + /** @internal */ + void mouseMove (const MouseEvent& e); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + bool hitTest (int x, int y); - This only applies to linear bars, and won't affect two- or three- value - sliders. - */ - void setSliderSnapsToMousePosition (const bool shouldSnapToMouse) throw(); +private: + Component* const component; + ComponentBoundsConstrainer* constrainer; + BorderSize borderSize; + int originalX, originalY, originalW, originalH; + int mouseZone; - /** If enabled, this gives the slider a pop-up bubble which appears while the - slider is being dragged. + void updateMouseZone (const MouseEvent& e) throw(); - This can be handy if your slider doesn't have a text-box, so that users can - see the value just when they're changing it. + ResizableBorderComponent (const ResizableBorderComponent&); + const ResizableBorderComponent& operator= (const ResizableBorderComponent&); +}; - If you pass a component as the parentComponentToUse parameter, the pop-up - bubble will be added as a child of that component when it's needed. If you - pass 0, the pop-up will be placed on the desktop instead (note that it's a - transparent window, so if you're using an OS that can't do transparent windows - you'll have to add it to a parent component instead). - */ - void setPopupDisplayEnabled (const bool isEnabled, - Component* const parentComponentToUse) throw(); +#endif // __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ResizableBorderComponent.h *********/ - /** If this is set to true, then right-clicking on the slider will pop-up - a menu to let the user change the way it works. +/********* Start of inlined file: juce_ResizableCornerComponent.h *********/ +#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ +#define __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ - By default this is turned off, but when turned on, the menu will include - things like velocity sensitivity, and for rotary sliders, whether they - use a linear or rotary mouse-drag to move them. - */ - void setPopupMenuEnabled (const bool menuEnabled) throw(); +/** A component that resizes a parent window when dragged. - /** This can be used to stop the mouse scroll-wheel from moving the slider. + This is the small triangular stripey resizer component you get in the bottom-right + of windows (more commonly on the Mac than Windows). Put one in the corner of + a larger component and it will automatically resize its parent when it gets dragged + around. - By default it's enabled. - */ - void setScrollWheelEnabled (const bool enabled) throw(); + @see ResizableFrameComponent +*/ +class JUCE_API ResizableCornerComponent : public Component +{ +public: - /** Returns a number to indicate which thumb is currently being dragged by the - mouse. + /** Creates a resizer. - This will return 0 for the main thumb, 1 for the minimum-value thumb, 2 for - the maximum-value thumb, or -1 if none is currently down. - */ - int getThumbBeingDragged() const throw() { return sliderBeingDragged; } + Pass in the target component which you want to be resized when this one is + dragged. - /** Callback to indicate that the user is about to start dragging the slider. + The target component will usually be a parent of the resizer component, but this + isn't mandatory. - @see SliderListener::sliderDragStarted - */ - virtual void startedDragging(); + Remember that when the target component is resized, it'll need to move and + resize this component to keep it in place, as this won't happen automatically. - /** Callback to indicate that the user has just stopped dragging the slider. + If the constrainer parameter is non-zero, then this object will be used to enforce + limits on the size and position that the component can be stretched to. Make sure + that the constrainer isn't deleted while still in use by this object. If you + pass a zero in here, no limits will be put on the sizes it can be stretched to. - @see SliderListener::sliderDragEnded + @see ComponentBoundsConstrainer */ - virtual void stoppedDragging(); + ResizableCornerComponent (Component* const componentToResize, + ComponentBoundsConstrainer* const constrainer); - /** Callback to indicate that the user has just moved the slider. + /** Destructor. */ + ~ResizableCornerComponent(); - @see SliderListener::sliderValueChanged - */ - virtual void valueChanged(); + juce_UseDebuggingNewOperator - /** Callback to indicate that the user has just moved the slider. - Note - the valueChanged() method has changed its format and now no longer has - any parameters. Update your code to use the new version. - This version has been left here with an int as its return value to cause - a syntax error if you've got existing code that uses the old version. - */ - virtual int valueChanged (double) { jassertfalse; return 0; } +protected: + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + bool hitTest (int x, int y); - /** Subclasses can override this to convert a text string to a value. +private: - When the user enters something into the text-entry box, this method is - called to convert it to a value. + Component* const component; + ComponentBoundsConstrainer* constrainer; + int originalX, originalY, originalW, originalH; - The default routine just tries to convert it to a double. + ResizableCornerComponent (const ResizableCornerComponent&); + const ResizableCornerComponent& operator= (const ResizableCornerComponent&); +}; - @see getTextFromValue - */ - virtual double getValueFromText (const String& text); +#endif // __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ResizableCornerComponent.h *********/ - /** Turns the slider's current value into a text string. +/** + A base class for top-level windows that can be dragged around and resized. - Subclasses can override this to customise the formatting of the text-entry box. + To add content to the window, use its setContentComponent() method to + give it a component that will remain positioned inside it (leaving a gap around + the edges for a border). - The default implementation just turns the value into a string, using - a number of decimal places based on the range interval. If a suffix string - has been set using setTextValueSuffix(), this will be appended to the text. + It's not advisable to add child components directly to a ResizableWindow: put them + inside your content component instead. And overriding methods like resized(), moved(), etc + is also not recommended - instead override these methods for your content component. + (If for some obscure reason you do need to override these methods, always remember to + call the super-class's resized() method too, otherwise it'll fail to lay out the window + decorations correctly). - @see getValueFromText - */ - virtual const String getTextFromValue (double value); + By default resizing isn't enabled - use the setResizable() method to enable it and + to choose the style of resizing to use. - /** Sets a suffix to append to the end of the numeric value when it's displayed as - a string. + @see TopLevelWindow +*/ +class JUCE_API ResizableWindow : public TopLevelWindow +{ +public: - This is used by the default implementation of getTextFromValue(), and is just - appended to the numeric value. For more advanced formatting, you can override - getTextFromValue() and do something else. + /** Creates a ResizableWindow. + + This constructor doesn't specify a background colour, so the LookAndFeel's default + background colour will be used. + + @param name the name to give the component + @param addToDesktop if true, the window will be automatically added to the + desktop; if false, you can use it as a child component */ - void setTextValueSuffix (const String& suffix); + ResizableWindow (const String& name, + const bool addToDesktop); - /** Allows a user-defined mapping of distance along the slider to its value. + /** Creates a ResizableWindow. - The default implementation for this performs the skewing operation that - can be set up in the setSkewFactor() method. Override it if you need - some kind of custom mapping instead, but make sure you also implement the - inverse function in valueToProportionOfLength(). + @param name the name to give the component + @param backgroundColour the colour to use for filling the window's background. + @param addToDesktop if true, the window will be automatically added to the + desktop; if false, you can use it as a child component + */ + ResizableWindow (const String& name, + const Colour& backgroundColour, + const bool addToDesktop); - @param proportion a value 0 to 1.0, indicating a distance along the slider - @returns the slider value that is represented by this position - @see valueToProportionOfLength + /** Destructor. + + If a content component has been set with setContentComponent(), it + will be deleted. */ - virtual double proportionOfLengthToValue (double proportion); + ~ResizableWindow(); - /** Allows a user-defined mapping of value to the position of the slider along its length. + /** Returns the colour currently being used for the window's background. - The default implementation for this performs the skewing operation that - can be set up in the setSkewFactor() method. Override it if you need - some kind of custom mapping instead, but make sure you also implement the - inverse function in proportionOfLengthToValue(). + As a convenience the window will fill itself with this colour, but you + can override the paint() method if you need more customised behaviour. - @param value a valid slider value, between the range of values specified in - setRange() - @returns a value 0 to 1.0 indicating the distance along the slider that - represents this value - @see proportionOfLengthToValue + This method is the same as retrieving the colour for ResizableWindow::backgroundColourId. + + @see setBackgroundColour */ - virtual double valueToProportionOfLength (double value); + const Colour getBackgroundColour() const throw(); - /** Returns the X or Y coordinate of a value along the slider's length. + /** Changes the colour currently being used for the window's background. - If the slider is horizontal, this will be the X coordinate of the given - value, relative to the left of the slider. If it's vertical, then this will - be the Y coordinate, relative to the top of the slider. + As a convenience the window will fill itself with this colour, but you + can override the paint() method if you need more customised behaviour. - If the slider is rotary, this will throw an assertion and return 0. If the - value is out-of-range, it will be constrained to the length of the slider. - */ - float getPositionOfValue (const double value); + Note that the opaque state of this window is altered by this call to reflect + the opacity of the colour passed-in. On window systems which can't support + semi-transparent windows this might cause problems, (though it's unlikely you'll + be using this class as a base for a semi-transparent component anyway). - /** This can be overridden to allow the slider to snap to user-definable values. + You can also use the ResizableWindow::backgroundColourId colour id to set + this colour. - If overridden, it will be called when the user tries to move the slider to - a given position, and allows a subclass to sanity-check this value, possibly - returning a different value to use instead. + @see getBackgroundColour + */ + void setBackgroundColour (const Colour& newColour); - @param attemptedValue the value the user is trying to enter - @param userIsDragging true if the user is dragging with the mouse; false if - they are entering the value using the text box - @returns the value to use instead + /** Make the window resizable or fixed. + + @param shouldBeResizable whether it's resizable at all + @param useBottomRightCornerResizer if true, it'll add a ResizableCornerComponent at the + bottom-right; if false, it'll use a ResizableBorderComponent + around the edge + @see setResizeLimits, isResizable */ - virtual double snapValue (double attemptedValue, const bool userIsDragging); + void setResizable (const bool shouldBeResizable, + const bool useBottomRightCornerResizer); - /** This can be called to force the text box to update its contents. + /** True if resizing is enabled. - (Not normally needed, as this is done automatically). + @see setResizable */ - void updateText(); + bool isResizable() const throw(); - /** True if the slider moves horizontally. */ - bool isHorizontal() const throw(); - /** True if the slider moves vertically. */ - bool isVertical() const throw(); + /** This sets the maximum and minimum sizes for the window. - /** A set of colour IDs to use to change the colour of various aspects of the slider. + If the window's current size is outside these limits, it will be resized to + make sure it's within them. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + Calling setBounds() on the component will bypass any size checking - it's only when + the window is being resized by the user that these values are enforced. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + @see setResizable, setFixedAspectRatio */ - enum ColourIds - { - backgroundColourId = 0x1001200, /**< A colour to use to fill the slider's background. */ - thumbColourId = 0x1001300, /**< The colour to draw the thumb with. It's up to the look - and feel class how this is used. */ - trackColourId = 0x1001310, /**< The colour to draw the groove that the thumb moves along. */ - rotarySliderFillColourId = 0x1001311, /**< For rotary sliders, this colour fills the outer curve. */ - rotarySliderOutlineColourId = 0x1001312, /**< For rotary sliders, this colour is used to draw the outer curve's outline. */ + void setResizeLimits (const int newMinimumWidth, + const int newMinimumHeight, + const int newMaximumWidth, + const int newMaximumHeight) throw(); - textBoxTextColourId = 0x1001400, /**< The colour for the text in the text-editor box used for editing the value. */ - textBoxBackgroundColourId = 0x1001500, /**< The background colour for the text-editor box. */ - textBoxHighlightColourId = 0x1001600, /**< The text highlight colour for the text-editor box. */ - textBoxOutlineColourId = 0x1001700 /**< The colour to use for a border around the text-editor box. */ - }; + /** Returns the bounds constrainer object that this window is using. - juce_UseDebuggingNewOperator + You can access this to change its properties. + */ + ComponentBoundsConstrainer* getConstrainer() throw() { return constrainer; } -protected: - /** @internal */ - void labelTextChanged (Label*); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - void mouseDoubleClick (const MouseEvent& e); - /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - /** @internal */ - void modifierKeysChanged (const ModifierKeys& modifiers); - /** @internal */ - void buttonClicked (Button* button); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - void enablementChanged(); - /** @internal */ - void focusOfChildComponentChanged (FocusChangeType cause); - /** @internal */ - void handleAsyncUpdate(); - /** @internal */ - void colourChanged(); - -private: - SortedSet listeners; - double currentValue, valueMin, valueMax; - double minimum, maximum, interval, doubleClickReturnValue; - double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle; - double velocityModeSensitivity, velocityModeOffset, minMaxDiff; - int velocityModeThreshold; - float rotaryStart, rotaryEnd; - int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; - int mouseDragStartX, mouseDragStartY; - int sliderRegionStart, sliderRegionSize; - int sliderBeingDragged; - int pixelsForFullDragExtent; - Rectangle sliderRect; - String textSuffix; - - SliderStyle style; - TextEntryBoxPosition textBoxPos; - int textBoxWidth, textBoxHeight; - IncDecButtonMode incDecButtonMode; - - bool editableText : 1, doubleClickToValue : 1; - bool isVelocityBased : 1, userKeyOverridesVelocity : 1, rotaryStop : 1; - bool incDecButtonsSideBySide : 1, sendChangeOnlyOnRelease : 1, popupDisplayEnabled : 1; - bool menuEnabled : 1, menuShown : 1, mouseWasHidden : 1, incDecDragged : 1; - bool scrollWheelEnabled : 1, snapsToMousePos : 1; - Font font; - Label* valueBox; - Button* incButton; - Button* decButton; - Component* popupDisplay; - Component* parentForPopupDisplay; - - float getLinearSliderPos (const double value); - void restoreMouseIfHidden(); - void sendDragStart(); - void sendDragEnd(); - double constrainedValue (double value) const throw(); - void triggerChangeMessage (const bool synchronous); - bool incDecDragDirectionIsHorizontal() const throw(); - - Slider (const Slider&); - const Slider& operator= (const Slider&); -}; - -#endif // __JUCE_SLIDER_JUCEHEADER__ -/********* End of inlined file: juce_Slider.h *********/ - -#endif -#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ + /** Sets the bounds-constrainer object to use for resizing and dragging this window. -#endif -#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ + A pointer to the object you pass in will be kept, but it won't be deleted + by this object, so it's the caller's responsiblity to manage it. -/********* Start of inlined file: juce_TableHeaderComponent.h *********/ -#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ -#define __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ + If you pass 0, then no contraints will be placed on the positioning of the window. + */ + void setConstrainer (ComponentBoundsConstrainer* newConstrainer); -class TableHeaderComponent; + /** Calls the window's setBounds method, after first checking these bounds + with the current constrainer. -/** - Receives events from a TableHeaderComponent when columns are resized, moved, etc. + @see setConstrainer + */ + void setBoundsConstrained (int x, int y, int width, int height); - You can register one of these objects for table events using TableHeaderComponent::addListener() - and TableHeaderComponent::removeListener(). + /** Returns true if the window is currently in full-screen mode. - @see TableHeaderComponent -*/ -class JUCE_API TableHeaderListener -{ -public: + @see setFullScreen + */ + bool isFullScreen() const; - TableHeaderListener() {} + /** Puts the window into full-screen mode, or restores it to its normal size. - /** Destructor. */ - virtual ~TableHeaderListener() {} + If true, the window will become full-screen; if false, it will return to the + last size it was before being made full-screen. - /** This is called when some of the table's columns are added, removed, hidden, - or rearranged. + @see isFullScreen */ - virtual void tableColumnsChanged (TableHeaderComponent* tableHeader) = 0; + void setFullScreen (const bool shouldBeFullScreen); - /** This is called when one or more of the table's columns are resized. - */ - virtual void tableColumnsResized (TableHeaderComponent* tableHeader) = 0; + /** Returns true if the window is currently minimised. - /** This is called when the column by which the table should be sorted is changed. + @see setMinimised */ - virtual void tableSortOrderChanged (TableHeaderComponent* tableHeader) = 0; + bool isMinimised() const; - /** This is called when the user begins or ends dragging one of the columns around. + /** Minimises the window, or restores it to its previous position and size. - When the user starts dragging a column, this is called with the ID of that - column. When they finish dragging, it is called again with 0 as the ID. - */ - virtual void tableColumnDraggingChanged (TableHeaderComponent* tableHeader, - int columnIdNowBeingDragged); -}; + When being un-minimised, it'll return to the last position and size it + was in before being minimised. -/** - A component that displays a strip of column headings for a table, and allows these - to be resized, dragged around, etc. + @see isMinimised + */ + void setMinimised (const bool shouldMinimise); - This is just the component that goes at the top of a table. You can use it - directly for custom components, or to create a simple table, use the - TableListBox class. + /** Returns a string which encodes the window's current size and position. - To use one of these, create it and use addColumn() to add all the columns that you need. - Each column must be given a unique ID number that's used to refer to it. + This string will encapsulate the window's size, position, and whether it's + in full-screen mode. It's intended for letting your application save and + restore a window's position. - @see TableListBox, TableHeaderListener -*/ -class JUCE_API TableHeaderComponent : public Component, - private AsyncUpdater -{ -public: + Use the restoreWindowStateFromString() to restore from a saved state. - /** Creates an empty table header. + @see restoreWindowStateFromString */ - TableHeaderComponent(); + const String getWindowStateAsString(); - /** Destructor. */ - ~TableHeaderComponent(); + /** Restores the window to a previously-saved size and position. - /** A combination of these flags are passed into the addColumn() method to specify - the properties of a column. + This restores the window's size, positon and full-screen status from an + string that was previously created with the getWindowStateAsString() + method. + + @returns false if the string wasn't a valid window state + @see getWindowStateAsString */ - enum ColumnPropertyFlags - { - visible = 1, /**< If this is set, the column will be shown; if not, it will be hidden until the user enables it with the pop-up menu. */ - resizable = 2, /**< If this is set, the column can be resized by dragging it. */ - draggable = 4, /**< If this is set, the column can be dragged around to change its order in the table. */ - appearsOnColumnMenu = 8, /**< If this is set, the column will be shown on the pop-up menu allowing it to be hidden/shown. */ - sortable = 16, /**< If this is set, then clicking on the column header will set it to be the sort column, and clicking again will reverse the order. */ - sortedForwards = 32, /**< If this is set, the column is currently the one by which the table is sorted (forwards). */ - sortedBackwards = 64, /**< If this is set, the column is currently the one by which the table is sorted (backwards). */ + bool restoreWindowStateFromString (const String& previousState); - /** This set of default flags is used as the default parameter value in addColumn(). */ - defaultFlags = (visible | resizable | draggable | appearsOnColumnMenu | sortable), + /** Returns the current content component. - /** A quick way of combining flags for a column that's not resizable. */ - notResizable = (visible | draggable | appearsOnColumnMenu | sortable), + This will be the component set by setContentComponent(), or 0 if none + has yet been specified. - /** A quick way of combining flags for a column that's not resizable or sortable. */ - notResizableOrSortable = (visible | draggable | appearsOnColumnMenu), + @see setContentComponent + */ + Component* getContentComponent() const throw() { return contentComponent; } - /** A quick way of combining flags for a column that's not sortable. */ - notSortable = (visible | resizable | draggable | appearsOnColumnMenu) - }; + /** Changes the current content component. - /** Adds a column to the table. + This sets a component that will be placed in the centre of the ResizableWindow, + (leaving a space around the edge for the border). - This will add a column, and asynchronously call the tableColumnsChanged() method of any - registered listeners. + You should never add components directly to a ResizableWindow (or any of its subclasses) + with addChildComponent(). Instead, add them to the content component. - @param columnName the name of the new column. It's ok to have two or more columns with the same name - @param columnId an ID for this column. The ID can be any number apart from 0, but every column must have - a unique ID. This is used to identify the column later on, after the user may have - changed the order that they appear in - @param width the initial width of the column, in pixels - @param maximumWidth a maximum width that the column can take when the user is resizing it. This only applies - if the 'resizable' flag is specified for this column - @param minimumWidth a minimum width that the column can take when the user is resizing it. This only applies - if the 'resizable' flag is specified for this column - @param propertyFlags a combination of some of the values from the ColumnPropertyFlags enum, to define the - properties of this column - @param insertIndex the index at which the column should be added. A value of 0 puts it at the start (left-hand side) - and -1 puts it at the end (right-hand size) of the table. Note that the index the index within - all columns, not just the index amongst those that are currently visible + @param newContentComponent the new component to use (or null to not use one) - this + component will be deleted either when replaced by another call + to this method, or when the ResizableWindow is deleted. + To remove a content component without deleting it, use + setContentComponent (0, false). + @param deleteOldOne if true, the previous content component will be deleted; if + false, the previous component will just be removed without + deleting it. + @param resizeToFit if true, the ResizableWindow will maintain its size such that + it always fits around the size of the content component. If false, the + new content will be resized to fit the current space available. */ - void addColumn (const String& columnName, - const int columnId, - const int width, - const int minimumWidth = 30, - const int maximumWidth = -1, - const int propertyFlags = defaultFlags, - const int insertIndex = -1); + void setContentComponent (Component* const newContentComponent, + const bool deleteOldOne = true, + const bool resizeToFit = false); - /** Removes a column with the given ID. + /** Changes the window so that the content component ends up with the specified size. - If there is such a column, this will asynchronously call the tableColumnsChanged() method of any - registered listeners. + This is basically a setSize call on the window, but which adds on the borders, + so you can specify the content component's target size. */ - void removeColumn (const int columnIdToRemove); + void setContentComponentSize (int width, int height); - /** Deletes all columns from the table. + /** A set of colour IDs to use to change the colour of various aspects of the window. - If there are any columns to remove, this will asynchronously call the tableColumnsChanged() method of any - registered listeners. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void removeAllColumns(); + enum ColourIds + { + backgroundColourId = 0x1005700, /**< A colour to use to fill the window's background. */ + }; - /** Returns the number of columns in the table. + juce_UseDebuggingNewOperator - If onlyCountVisibleColumns is true, this will return the number of visible columns; otherwise it'll - return the total number of columns, including hidden ones. +protected: + /** @internal */ + void paint (Graphics& g); + /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ + void moved(); + /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ + void resized(); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + void childBoundsChanged (Component* child); + /** @internal */ + void parentSizeChanged(); + /** @internal */ + void visibilityChanged(); + /** @internal */ + void activeWindowStatusChanged(); + /** @internal */ + int getDesktopWindowStyleFlags() const; - @see isColumnVisible - */ - int getNumColumns (const bool onlyCountVisibleColumns) const throw(); + /** Returns the width of the border to use around the window. - /** Returns the name for a column. - @see setColumnName + @see getContentComponentBorder */ - const String getColumnName (const int columnId) const throw(); - - /** Changes the name of a column. */ - void setColumnName (const int columnId, const String& newName); + virtual const BorderSize getBorderThickness(); - /** Moves a column to a different index in the table. + /** Returns the insets to use when positioning the content component. - @param columnId the column to move - @param newVisibleIndex the target index for it, from 0 to the number of columns currently visible. + @see getBorderThickness */ - void moveColumn (const int columnId, int newVisibleIndex); + virtual const BorderSize getContentComponentBorder(); - /** Returns the width of one of the columns. - */ - int getColumnWidth (const int columnId) const throw(); +#ifdef JUCE_DEBUG + /** Overridden to warn people about adding components directly to this component + instead of using setContentComponent(). - /** Changes the width of a column. + If you know what you're doing and are sure you really want to add a component, specify + a base-class method call to Component::addAndMakeVisible(), to side-step this warning. + */ + void addChildComponent (Component* const child, int zOrder = -1); + /** Overridden to warn people about adding components directly to this component + instead of using setContentComponent(). - This will cause an asynchronous callback to the tableColumnsResized() method of any registered listeners. + If you know what you're doing and are sure you really want to add a component, specify + a base-class method call to Component::addAndMakeVisible(), to side-step this warning. */ - void setColumnWidth (const int columnId, const int newWidth); + void addAndMakeVisible (Component* const child, int zOrder = -1); - /** Shows or hides a column. +#endif - This can cause an asynchronous callback to the tableColumnsChanged() method of any registered listeners. - @see isColumnVisible - */ - void setColumnVisible (const int columnId, const bool shouldBeVisible); + ResizableCornerComponent* resizableCorner; + ResizableBorderComponent* resizableBorder; - /** Returns true if this column is currently visible. - @see setColumnVisible - */ - bool isColumnVisible (const int columnId) const; +private: + Component* contentComponent; + bool resizeToFitContent, fullscreen; + ComponentDragger dragger; + Rectangle lastNonFullScreenPos; + ComponentBoundsConstrainer defaultConstrainer; + ComponentBoundsConstrainer* constrainer; + #ifdef JUCE_DEBUG + bool hasBeenResized; + #endif - /** Changes the column which is the sort column. + void updateLastPos(); - This can cause an asynchronous callback to the tableSortOrderChanged() method of any registered listeners. + ResizableWindow (const ResizableWindow&); + const ResizableWindow& operator= (const ResizableWindow&); - If this method doesn't actually change the column ID, then no re-sort will take place (you can - call reSortTable() to force a re-sort to happen if you've modified the table's contents). + // (xxx remove these eventually) + // temporarily here to stop old code compiling, as the parameters for these methods have changed.. + void getBorderThickness (int& left, int& top, int& right, int& bottom); + // temporarily here to stop old code compiling, as the parameters for these methods have changed.. + void getContentComponentBorder (int& left, int& top, int& right, int& bottom); +}; - @see getSortColumnId, isSortedForwards, reSortTable - */ - void setSortColumnId (const int columnId, const bool sortForwards); +#endif // __JUCE_RESIZABLEWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_ResizableWindow.h *********/ - /** Returns the column ID by which the table is currently sorted, or 0 if it is unsorted. +/********* Start of inlined file: juce_GlyphArrangement.h *********/ +#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ +#define __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ - @see setSortColumnId, isSortedForwards - */ - int getSortColumnId() const throw(); +/** + A glyph from a particular font, with a particular size, style, + typeface and position. - /** Returns true if the table is currently sorted forwards, or false if it's backwards. - @see setSortColumnId - */ - bool isSortedForwards() const throw(); + @see GlyphArrangement, Font +*/ +class JUCE_API PositionedGlyph +{ +public: - /** Triggers a re-sort of the table according to the current sort-column. + /** Returns the character the glyph represents. */ + juce_wchar getCharacter() const throw() { return character; } + /** Checks whether the glyph is actually empty. */ + bool isWhitespace() const throw() { return CharacterFunctions::isWhitespace (character); } - If you modifiy the table's contents, you can call this to signal that the table needs - to be re-sorted. + /** Returns the position of the glyph's left-hand edge. */ + float getLeft() const throw() { return x; } + /** Returns the position of the glyph's right-hand edge. */ + float getRight() const throw() { return x + w; } + /** Returns the y position of the glyph's baseline. */ + float getBaselineY() const throw() { return y; } + /** Returns the y position of the top of the glyph. */ + float getTop() const throw() { return y - font.getAscent(); } + /** Returns the y position of the bottom of the glyph. */ + float getBottom() const throw() { return y + font.getDescent(); } - (This doesn't do any sorting synchronously - it just asynchronously sends a call to the - tableSortOrderChanged() method of any listeners). - */ - void reSortTable(); + /** Shifts the glyph's position by a relative amount. */ + void moveBy (const float deltaX, + const float deltaY) throw(); - /** Returns the total width of all the visible columns in the table. - */ - int getTotalWidth() const throw(); + /** Draws the glyph into a graphics context. */ + void draw (const Graphics& g) const throw(); - /** Returns the index of a given column. + /** Draws the glyph into a graphics context, with an extra transform applied to it. */ + void draw (const Graphics& g, const AffineTransform& transform) const throw(); - If there's no such column ID, this will return -1. + /** Returns the path for this glyph. - If onlyCountVisibleColumns is true, this will return the index amoungst the visible columns; - otherwise it'll return the index amongst all the columns, including any hidden ones. + @param path the glyph's outline will be appended to this path */ - int getIndexOfColumnId (const int columnId, const bool onlyCountVisibleColumns) const throw(); + void createPath (Path& path) const throw(); - /** Returns the ID of the column at a given index. + /** Checks to see if a point lies within this glyph. */ + bool hitTest (float x, float y) const throw(); - If onlyCountVisibleColumns is true, this will count the index amoungst the visible columns; - otherwise it'll count it amongst all the columns, including any hidden ones. + juce_UseDebuggingNewOperator - If the index is out-of-range, it'll return 0. - */ - int getColumnIdOfIndex (int index, const bool onlyCountVisibleColumns) const throw(); +private: - /** Returns the rectangle containing of one of the columns. + friend class GlyphArrangement; + float x, y, w; + Font font; + juce_wchar character; + int glyph; - The index is an index from 0 to the number of columns that are currently visible (hidden - ones are not counted). It returns a rectangle showing the position of the column relative - to this component's top-left. If the index is out-of-range, an empty rectangle is retrurned. - */ - const Rectangle getColumnPosition (const int index) const throw(); + PositionedGlyph() throw(); +}; - /** Finds the column ID at a given x-position in the component. +/** + A set of glyphs, each with a position. - If there is a column at this point this returns its ID, or if not, it will return 0. - */ - int getColumnIdAtX (const int xToFind) const throw(); + You can create a GlyphArrangement, text to it and then draw it onto a + graphics context. It's used internally by the text methods in the + Graphics class, but can be used directly if more control is needed. - /** If set to true, this indicates that the columns should be expanded or shrunk to fill the - entire width of the component. + @see Font, PositionedGlyph +*/ +class JUCE_API GlyphArrangement +{ +public: - By default this is disabled. Turning it on also means that when resizing a column, those - on the right will be squashed to fit. - */ - void setStretchToFitActive (const bool shouldStretchToFit); + /** Creates an empty arrangement. */ + GlyphArrangement() throw(); - /** Returns true if stretch-to-fit has been enabled. - @see setStretchToFitActive - */ - bool isStretchToFitActive() const throw(); + /** Takes a copy of another arrangement. */ + GlyphArrangement (const GlyphArrangement& other) throw(); - /** If stretch-to-fit is enabled, this will resize all the columns to make them fit into the - specified width, keeping their relative proportions the same. + /** Copies another arrangement onto this one. - If the minimum widths of the columns are too wide to fit into this space, it may - actually end up wider. + To add another arrangement without clearing this one, use addGlyphArrangement(). */ - void resizeAllColumnsToFit (int targetTotalWidth); + const GlyphArrangement& operator= (const GlyphArrangement& other) throw(); - /** Enables or disables the pop-up menu. + /** Destructor. */ + ~GlyphArrangement() throw(); - The default menu allows the user to show or hide columns. You can add custom - items to this menu by overloading the addMenuItems() and reactToMenuItem() methods. + /** Returns the total number of glyphs in the arrangement. */ + int getNumGlyphs() const throw() { return glyphs.size(); } - By default the menu is enabled. + /** Returns one of the glyphs from the arrangement. - @see isPopupMenuActive, addMenuItems, reactToMenuItem + @param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be + careful not to pass an out-of-range index here, as it + doesn't do any bounds-checking. */ - void setPopupMenuActive (const bool hasMenu); + PositionedGlyph& getGlyph (const int index) const throw(); - /** Returns true if the pop-up menu is enabled. - @see setPopupMenuActive + /** Clears all text from the arrangement and resets it. */ - bool isPopupMenuActive() const throw(); + void clear() throw(); - /** Returns a string that encapsulates the table's current layout. + /** Appends a line of text to the arrangement. - This can be restored later using restoreFromString(). It saves the order of - the columns, the currently-sorted column, and the widths. + This will add the text as a single line, where x is the left-hand edge of the + first character, and y is the position for the text's baseline. - @see restoreFromString - */ - const String toString() const; - - /** Restores the state of the table, based on a string previously created with - toString(). - - @see toString + If the text contains new-lines or carriage-returns, this will ignore them - use + addJustifiedText() to add multi-line arrangements. */ - void restoreFromString (const String& storedVersion); - - /** Adds a listener to be informed about things that happen to the header. */ - void addListener (TableHeaderListener* const newListener) throw(); - - /** Removes a previously-registered listener. */ - void removeListener (TableHeaderListener* const listenerToRemove) throw(); + void addLineOfText (const Font& font, + const String& text, + const float x, + const float y) throw(); - /** This can be overridden to handle a mouse-click on one of the column headers. + /** Adds a line of text, truncating it if it's wider than a specified size. - The default implementation will use this click to call getSortColumnId() and - change the sort order. + This is the same as addLineOfText(), but if the line's width exceeds the value + specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."), + if useEllipsis is true, or if this is false, it will just drop any subsequent characters. */ - virtual void columnClicked (int columnId, const ModifierKeys& mods); + void addCurtailedLineOfText (const Font& font, + const String& text, + float x, + const float y, + const float maxWidthPixels, + const bool useEllipsis) throw(); - /** This can be overridden to add custom items to the pop-up menu. + /** Adds some multi-line text, breaking lines at word-boundaries if they are too wide. - If you override this, you should call the superclass's method to add its - column show/hide items, if you want them on the menu as well. + This will add text to the arrangement, breaking it into new lines either where there + is a new-line or carriage-return character in the text, or where a line's width + exceeds the value set in maxLineWidth. - Then to handle the result, override reactToMenuItem(). + Each line that is added will be laid out using the flags set in horizontalLayout, so + the lines can be left- or right-justified, or centred horizontally in the space + between x and (x + maxLineWidth). - @see reactToMenuItem + The y co-ordinate is the position of the baseline of the first line of text - subsequent + lines will be placed below it, separated by a distance of font.getHeight(). */ - virtual void addMenuItems (PopupMenu& menu, const int columnIdClicked); - - /** Override this to handle any custom items that you have added to the - pop-up menu with an addMenuItems() override. - - If the menuReturnId isn't one of your own custom menu items, you'll need to - call TableHeaderComponent::reactToMenuItem() to allow the base class to - handle the items that it had added. + void addJustifiedText (const Font& font, + const String& text, + float x, float y, + const float maxLineWidth, + const Justification& horizontalLayout) throw(); - @see addMenuItems - */ - virtual void reactToMenuItem (const int menuReturnId, const int columnIdClicked); + /** Tries to fit some text withing a given space. - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void mouseMove (const MouseEvent&); - /** @internal */ - void mouseEnter (const MouseEvent&); - /** @internal */ - void mouseExit (const MouseEvent&); - /** @internal */ - void mouseDown (const MouseEvent&); - /** @internal */ - void mouseDrag (const MouseEvent&); - /** @internal */ - void mouseUp (const MouseEvent&); - /** @internal */ - const MouseCursor getMouseCursor(); + This does its best to make the given text readable within the specified rectangle, + so it useful for labelling things. - /** Can be overridden for more control over the pop-up menu behaviour. */ - virtual void showColumnChooserMenu (const int columnIdClicked); + If the text is too big, it'll be squashed horizontally or broken over multiple lines + if the maximumLinesToUse value allows this. If the text just won't fit into the space, + it'll cram as much as possible in there, and put some ellipsis at the end to show that + it's been truncated. - juce_UseDebuggingNewOperator + A Justification parameter lets you specify how the text is laid out within the rectangle, + both horizontally and vertically. -private: - struct ColumnInfo - { - String name; - int id, propertyFlags, width, minimumWidth, maximumWidth; - double lastDeliberateWidth; + @see Graphics::drawFittedText + */ + void addFittedText (const Font& font, + const String& text, + const float x, const float y, + const float width, const float height, + const Justification& layout, + int maximumLinesToUse, + const float minimumHorizontalScale = 0.7f) throw(); - bool isVisible() const throw(); - }; + /** Appends another glyph arrangement to this one. */ + void addGlyphArrangement (const GlyphArrangement& other) throw(); - OwnedArray columns; - Array listeners; - Component* dragOverlayComp; + /** Draws this glyph arrangement to a graphics context. - bool columnsChanged, columnsResized, sortChanged, menuActive, stretchToFit; - int columnIdBeingResized, columnIdBeingDragged, initialColumnWidth; - int columnIdUnderMouse, draggingColumnOffset, draggingColumnOriginalIndex, lastDeliberateWidth; + This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&) + method, which renders the glyphs as filled vectors. + */ + void draw (const Graphics& g) const throw(); - ColumnInfo* getInfoForId (const int columnId) const throw(); - int visibleIndexToTotalIndex (const int visibleIndex) const throw(); - void sendColumnsChanged(); - void handleAsyncUpdate(); - void beginDrag (const MouseEvent&); - void endDrag (const int finalIndex); - int getResizeDraggerAt (const int mouseX) const throw(); - void updateColumnUnderMouse (int x, int y); - void resizeColumnsToFit (int firstColumnIndex, int targetTotalWidth); + /** Draws this glyph arrangement to a graphics context. - TableHeaderComponent (const TableHeaderComponent&); - const TableHeaderComponent operator= (const TableHeaderComponent&); -}; + This renders the paths as filled vectors, so is far slower than the draw (Graphics&) + method for non-transformed arrangements. + */ + void draw (const Graphics& g, const AffineTransform& transform) const throw(); -#endif // __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_TableHeaderComponent.h *********/ + /** Converts the set of glyphs into a path. -#endif -#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ + @param path the glyphs' outlines will be appended to this path + */ + void createPath (Path& path) const throw(); -/********* Start of inlined file: juce_TableListBox.h *********/ -#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ -#define __JUCE_TABLELISTBOX_JUCEHEADER__ + /** Looks for a glyph that contains the given co-ordinate. -/** - One of these is used by a TableListBox as the data model for the table's contents. + @returns the index of the glyph, or -1 if none were found. + */ + int findGlyphIndexAt (float x, float y) const throw(); - The virtual methods that you override in this class take care of drawing the - table cells, and reacting to events. + /** Finds the smallest rectangle that will enclose a subset of the glyphs. - @see TableListBox -*/ -class JUCE_API TableListBoxModel -{ -public: + @param startIndex the first glyph to test + @param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after + startIndex will be included + @param left on return, the leftmost co-ordinate of the rectangle + @param top on return, the top co-ordinate of the rectangle + @param right on return, the rightmost co-ordinate of the rectangle + @param bottom on return, the bottom co-ordinate of the rectangle + @param includeWhitespace if true, the extent of any whitespace characters will also + be taken into account + */ + void getBoundingBox (int startIndex, + int numGlyphs, + float& left, + float& top, + float& right, + float& bottom, + const bool includeWhitespace) const throw(); - TableListBoxModel() {} + /** Shifts a set of glyphs by a given amount. - /** Destructor. */ - virtual ~TableListBoxModel() {} + @param startIndex the first glyph to transform + @param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after + startIndex will be used + @param deltaX the amount to add to their x-positions + @param deltaY the amount to add to their y-positions + */ + void moveRangeOfGlyphs (int startIndex, int numGlyphs, + const float deltaX, + const float deltaY) throw(); - /** This must return the number of rows currently in the table. + /** Removes a set of glyphs from the arrangement. - If the number of rows changes, you must call TableListBox::updateContent() to - cause it to refresh the list. + @param startIndex the first glyph to remove + @param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after + startIndex will be deleted */ - virtual int getNumRows() = 0; + void removeRangeOfGlyphs (int startIndex, int numGlyphs) throw(); - /** This must draw the background behind one of the rows in the table. + /** Expands or compresses a set of glyphs horizontally. - The graphics context has its origin at the row's top-left, and your method - should fill the area specified by the width and height parameters. + @param startIndex the first glyph to transform + @param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after + startIndex will be used + @param horizontalScaleFactor how much to scale their horizontal width by */ - virtual void paintRowBackground (Graphics& g, - int rowNumber, - int width, int height, - bool rowIsSelected) = 0; + void stretchRangeOfGlyphs (int startIndex, int numGlyphs, + const float horizontalScaleFactor) throw(); - /** This must draw one of the cells. + /** Justifies a set of glyphs within a given space. - The graphics context's origin will already be set to the top-left of the cell, - whose size is specified by (width, height). + This moves the glyphs as a block so that the whole thing is located within the + given rectangle with the specified layout. + + If the Justification::horizontallyJustified flag is specified, each line will + be stretched out to fill the specified width. */ - virtual void paintCell (Graphics& g, - int rowNumber, - int columnId, - int width, int height, - bool rowIsSelected) = 0; + void justifyGlyphs (const int startIndex, const int numGlyphs, + const float x, + const float y, + const float width, + const float height, + const Justification& justification) throw(); - /** This is used to create or update a custom component to go in a cell. + juce_UseDebuggingNewOperator - Any cell may contain a custom component, or can just be drawn with the paintCell() method - and handle mouse clicks with cellClicked(). +private: + OwnedArray glyphs; - This method will be called whenever a custom component might need to be updated - e.g. - when the table is changed, or TableListBox::updateContent() is called. + int insertEllipsis (const Font& font, const float maxXPos, const int startIndex, int endIndex) throw(); + int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font& font, + const Justification& justification, float minimumHorizontalScale) throw(); + void spreadOutLine (const int start, const int numGlyphs, const float targetWidth) throw(); +}; - If you don't need a custom component for the specified cell, then return 0. +#endif // __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ +/********* End of inlined file: juce_GlyphArrangement.h *********/ - If you do want a custom component, and the existingComponentToUpdate is null, then - this method must create a new component suitable for the cell, and return it. +/** + A file open/save dialog box. - If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created - by this method. In this case, the method must either update it to make sure it's correctly representing - the given cell (which may be different from the one that the component was created for), or it can - delete this component and return a new one. - */ - virtual Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected, - Component* existingComponentToUpdate); + This is a Juce-based file dialog box; to use a native file chooser, see the + FileChooser class. - /** This callback is made when the user clicks on one of the cells in the table. + To use one of these, create it and call its show() method. e.g. - The mouse event's coordinates will be relative to the entire table row. - @see cellDoubleClicked, backgroundClicked - */ - virtual void cellClicked (int rowNumber, int columnId, const MouseEvent& e); + @code + { + WildcardFileFilter wildcardFilter (T("*.foo"), T("Foo files")); - /** This callback is made when the user clicks on one of the cells in the table. + FileBrowserComponent browser (FileBrowserComponent::loadFileMode, + File::nonexistent, + &wildcardFilter, + 0); - The mouse event's coordinates will be relative to the entire table row. - @see cellClicked, backgroundClicked - */ - virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent& e); + FileChooserDialogBox dialogBox (T("Open some kind of file"), + T("Please choose some kind of file that you want to open..."), + browser, + getLookAndFeel().alertWindowBackground); - /** This can be overridden to react to the user double-clicking on a part of the list where - there are no rows. + if (dialogBox.show()) + { + File selectedFile = browser.getCurrentFile(); + ... + } + } + @endcode - @see cellClicked - */ - virtual void backgroundClicked(); + @see FileChooser +*/ +class JUCE_API FileChooserDialogBox : public ResizableWindow, + public ButtonListener, + public FileBrowserListener +{ +public: - /** This callback is made when the table's sort order is changed. + /** Creates a file chooser box. - This could be because the user has clicked a column header, or because the - TableHeaderComponent::setSortColumnId() method was called. + @param title the main title to show at the top of the box + @param instructions an optional longer piece of text to show below the title in + a smaller font, describing in more detail what's required. + @param browserComponent a FileBrowserComponent that will be shown inside this dialog + box. Make sure you delete this after (but not before!) the + dialog box has been deleted. + @param warnAboutOverwritingExistingFiles if true, then the user will be asked to confirm + if they try to select a file that already exists. (This + flag is only used when saving files) + @param backgroundColour the background colour for the top level window - If you implement this, your method should re-sort the table using the given - column as the key. + @see FileBrowserComponent, FilePreviewComponent */ - virtual void sortOrderChanged (int newSortColumnId, const bool isForwards); + FileChooserDialogBox (const String& title, + const String& instructions, + FileBrowserComponent& browserComponent, + const bool warnAboutOverwritingExistingFiles, + const Colour& backgroundColour); - /** Returns the best width for one of the columns. + /** Destructor. */ + ~FileChooserDialogBox(); - If you implement this method, you should measure the width of all the items - in this column, and return the best size. + /** Displays and runs the dialog box modally. - Returning 0 means that the column shouldn't be changed. + This will show the box with the specified size, returning true if the user + pressed 'ok', or false if they cancelled. - This is used by TableListBox::autoSizeColumn() and TableListBox::autoSizeAllColumns(). + Leave the width or height as 0 to use the default size */ - virtual int getColumnAutoSizeWidth (int columnId); + bool show (int width = 0,int height = 0); - /** Returns a tooltip for a particular cell in the table. - */ - virtual const String getCellTooltip (int rowNumber, int columnId); + /** @internal */ + void buttonClicked (Button* button); + /** @internal */ + void closeButtonPressed(); + /** @internal */ + void selectionChanged(); + /** @internal */ + void fileClicked (const File& file, const MouseEvent& e); + /** @internal */ + void fileDoubleClicked (const File& file); - /** Override this to be informed when rows are selected or deselected. + juce_UseDebuggingNewOperator - @see ListBox::selectedRowsChanged() - */ - virtual void selectedRowsChanged (int lastRowSelected); +private: + class ContentComponent : public Component + { + public: + ContentComponent(); + ~ContentComponent(); - /** Override this to be informed when the delete key is pressed. + void paint (Graphics& g); + void resized(); - @see ListBox::deleteKeyPressed() - */ - virtual void deleteKeyPressed (int lastRowSelected); + String instructions; + GlyphArrangement text; - /** Override this to be informed when the return key is pressed. + FileBrowserComponent* chooserComponent; + FilePreviewComponent* previewComponent; + TextButton* okButton; + TextButton* cancelButton; + }; - @see ListBox::returnKeyPressed() - */ - virtual void returnKeyPressed (int lastRowSelected); + ContentComponent* content; + const bool warnAboutOverwritingExistingFiles; - /** Override this to be informed when the list is scrolled. + FileChooserDialogBox (const FileChooserDialogBox&); + const FileChooserDialogBox& operator= (const FileChooserDialogBox&); +}; - This might be caused by the user moving the scrollbar, or by programmatic changes - to the list position. - */ - virtual void listWasScrolled(); +#endif // __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ +/********* End of inlined file: juce_FileChooserDialogBox.h *********/ - /** To allow rows from your table to be dragged-and-dropped, implement this method. +#endif +#ifndef __JUCE_FILEFILTER_JUCEHEADER__ - If this returns a non-empty name then when the user drags a row, the table will try to - find a DragAndDropContainer in its parent hierarchy, and will use it to trigger a - drag-and-drop operation, using this string as the source description, and the listbox - itself as the source component. +#endif +#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ - @see DragAndDropContainer::startDragging - */ - virtual const String getDragSourceDescription (const SparseSet& currentlySelectedRows); -}; +/********* Start of inlined file: juce_FileListComponent.h *********/ +#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ +#define __JUCE_FILELISTCOMPONENT_JUCEHEADER__ /** - A table of cells, using a TableHeaderComponent as its header. + A component that displays the files in a directory as a listbox. - This component makes it easy to create a table by providing a TableListBoxModel as - the data source. + This implements the DirectoryContentsDisplayComponent base class so that + it can be used in a FileBrowserComponent. - @see TableListBoxModel, TableHeaderComponent + To attach a listener to it, use its DirectoryContentsDisplayComponent base + class and the FileBrowserListener class. + + @see DirectoryContentsList, FileTreeComponent */ -class JUCE_API TableListBox : public ListBox, - private ListBoxModel, - private TableHeaderListener +class JUCE_API FileListComponent : public ListBox, + public DirectoryContentsDisplayComponent, + private ListBoxModel, + private ChangeListener { public: - /** Creates a TableListBox. - - The model pointer passed-in can be null, in which case you can set it later - with setModel(). + /** Creates a listbox to show the contents of a specified directory. */ - TableListBox (const String& componentName, - TableListBoxModel* const model); + FileListComponent (DirectoryContentsList& listToShow); /** Destructor. */ - ~TableListBox(); - - /** Changes the TableListBoxModel that is being used for this table. - */ - void setModel (TableListBoxModel* const newModel); - - /** Returns the model currently in use. */ - TableListBoxModel* getModel() const throw() { return model; } - - /** Returns the header component being used in this table. */ - TableHeaderComponent* getHeader() const throw() { return header; } - - /** Changes the height of the table header component. - @see getHeaderHeight - */ - void setHeaderHeight (const int newHeight); - - /** Returns the height of the table header. - @see setHeaderHeight - */ - int getHeaderHeight() const throw(); - - /** Resizes a column to fit its contents. - - This uses TableListBoxModel::getColumnAutoSizeWidth() to find the best width, - and applies that to the column. - - @see autoSizeAllColumns, TableHeaderComponent::setColumnWidth - */ - void autoSizeColumn (const int columnId); - - /** Calls autoSizeColumn() for all columns in the table. */ - void autoSizeAllColumns(); - - /** Enables or disables the auto size options on the popup menu. - - By default, these are enabled. - */ - void setAutoSizeMenuOptionShown (const bool shouldBeShown); + ~FileListComponent(); - /** True if the auto-size options should be shown on the menu. - @see setAutoSizeMenuOptionsShown + /** Returns the number of files the user has got selected. + @see getSelectedFile */ - bool isAutoSizeMenuOptionShown() const throw(); - - /** Returns the position of one of the cells in the table. - - If relativeToComponentTopLeft is true, the co-ordinates are relative to - the table component's top-left. The row number isn't checked to see if it's - in-range, but the column ID must exist or this will return an empty rectangle. + int getNumSelectedFiles() const; - If relativeToComponentTopLeft is false, the co-ords are relative to the - top-left of the table's top-left cell. + /** Returns one of the files that the user has currently selected. + The index should be in the range 0 to (getNumSelectedFiles() - 1). + @see getNumSelectedFiles */ - const Rectangle getCellPosition (const int columnId, - const int rowNumber, - const bool relativeToComponentTopLeft) const; - - /** Scrolls horizontally if necessary to make sure that a particular column is visible. + const File getSelectedFile (int index = 0) const; - @see ListBox::scrollToEnsureRowIsOnscreen - */ - void scrollToEnsureColumnIsOnscreen (const int columnId); + /** Scrolls to the top of the list. */ + void scrollToTop(); + /** @internal */ + void changeListenerCallback (void*); /** @internal */ int getNumRows(); /** @internal */ @@ -48249,508 +47226,856 @@ public: void deleteKeyPressed (int currentSelectedRow); /** @internal */ void returnKeyPressed (int currentSelectedRow); - /** @internal */ - void backgroundClicked(); - /** @internal */ - void listWasScrolled(); - /** @internal */ - void tableColumnsChanged (TableHeaderComponent*); - /** @internal */ - void tableColumnsResized (TableHeaderComponent*); - /** @internal */ - void tableSortOrderChanged (TableHeaderComponent*); - /** @internal */ - void tableColumnDraggingChanged (TableHeaderComponent*, int); - /** @internal */ - void resized(); juce_UseDebuggingNewOperator private: - TableHeaderComponent* header; - TableListBoxModel* model; - int columnIdNowBeingDragged; - bool autoSizeOptionsShown; - - void updateColumnComponents() const; + FileListComponent (const FileListComponent&); + const FileListComponent& operator= (const FileListComponent&); - TableListBox (const TableListBox&); - const TableListBox& operator= (const TableListBox&); + File lastDirectory; }; -#endif // __JUCE_TABLELISTBOX_JUCEHEADER__ -/********* End of inlined file: juce_TableListBox.h *********/ +#endif // __JUCE_FILELISTCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FileListComponent.h *********/ #endif -#ifndef __JUCE_TOOLBAR_JUCEHEADER__ +#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ -#endif -#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ +/********* Start of inlined file: juce_FilenameComponent.h *********/ +#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ +#define __JUCE_FILENAMECOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ToolbarItemFactory.h *********/ -#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ -#define __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ +class FilenameComponent; /** - A factory object which can create ToolbarItemComponent objects. - - A subclass of ToolbarItemFactory publishes a set of types of toolbar item - that it can create. + Listens for events happening to a FilenameComponent. - Each type of item is identified by a unique ID, and multiple instances of an - item type can exist at once (even on the same toolbar, e.g. spacers or separator - bars). + Use FilenameComponent::addListener() and FilenameComponent::removeListener() to + register one of these objects for event callbacks when the filename is changed. - @see Toolbar, ToolbarItemComponent, ToolbarButton + @see FilenameComponent */ -class JUCE_API ToolbarItemFactory +class JUCE_API FilenameComponentListener { public: - - ToolbarItemFactory(); - /** Destructor. */ - virtual ~ToolbarItemFactory(); + virtual ~FilenameComponentListener() {} - /** A set of reserved item ID values, used for the built-in item types. - */ - enum SpecialItemIds - { - separatorBarId = -1, /**< The item ID for a vertical (or horizontal) separator bar that - can be placed between sets of items to break them into groups. */ - spacerId = -2, /**< The item ID for a fixed-width space that can be placed between - items.*/ - flexibleSpacerId = -3 /**< The item ID for a gap that pushes outwards against the things on - either side of it, filling any available space. */ - }; + /** This method is called after the FilenameComponent's file has been changed. */ + virtual void filenameComponentChanged (FilenameComponent* fileComponentThatHasChanged) = 0; +}; - /** Must return a list of the IDs for all the item types that this factory can create. +/** + Shows a filename as an editable text box, with a 'browse' button and a + drop-down list for recently selected files. - The ids should be added to the array that is passed-in. + A handy component for dialogue boxes where you want the user to be able to + select a file or directory. - An item ID can be any integer you choose, except for 0, which is considered a null ID, - and the predefined IDs in the SpecialItemIds enum. + Attach an FilenameComponentListener using the addListener() method, and it will + get called each time the user changes the filename, either by browsing for a file + and clicking 'ok', or by typing a new filename into the box and pressing return. - You should also add the built-in types (separatorBarId, spacerId and flexibleSpacerId) - to this list if you want your toolbar to be able to contain those items. + @see FileChooser, ComboBox +*/ +class JUCE_API FilenameComponent : public Component, + public SettableTooltipClient, + public FileDragAndDropTarget, + private AsyncUpdater, + private ButtonListener, + private ComboBoxListener +{ +public: - The list returned here is used by the ToolbarItemPalette class to obtain its list - of available items, and their order on the palette will reflect the order in which - they appear on this list. + /** Creates a FilenameComponent. - @see ToolbarItemPalette + @param name the name for this component. + @param currentFile the file to initially show in the box + @param canEditFilename if true, the user can manually edit the filename; if false, + they can only change it by browsing for a new file + @param isDirectory if true, the file will be treated as a directory, and + an appropriate directory browser used + @param isForSaving if true, the file browser will allow non-existent files to + be picked, as the file is assumed to be used for saving rather + than loading + @param fileBrowserWildcard a wildcard pattern to use in the file browser - e.g. "*.txt;*.foo". + If an empty string is passed in, then the pattern is assumed to be "*" + @param enforcedSuffix if this is non-empty, it is treated as a suffix that will be added + to any filenames that are entered or chosen + @param textWhenNothingSelected the message to display in the box before any filename is entered. (This + will only appear if the initial file isn't valid) */ - virtual void getAllToolbarItemIds (Array & ids) = 0; + FilenameComponent (const String& name, + const File& currentFile, + const bool canEditFilename, + const bool isDirectory, + const bool isForSaving, + const String& fileBrowserWildcard, + const String& enforcedSuffix, + const String& textWhenNothingSelected); - /** Must return the set of items that should be added to a toolbar as its default set. + /** Destructor. */ + ~FilenameComponent(); - This method is used by Toolbar::addDefaultItems() to determine which items to - create. + /** Returns the currently displayed filename. */ + const File getCurrentFile() const; - The items that your method adds to the array that is passed-in will be added to the - toolbar in the same order. Items can appear in the list more than once. + /** Changes the current filename. + + If addToRecentlyUsedList is true, the filename will also be added to the + drop-down list of recent files. + + If sendChangeNotification is false, then the listeners won't be told of the + change. */ - virtual void getDefaultItemSet (Array & ids) = 0; + void setCurrentFile (File newFile, + const bool addToRecentlyUsedList, + const bool sendChangeNotification = true); - /** Must create an instance of one of the items that the factory lists in its - getAllToolbarItemIds() method. + /** Changes whether the use can type into the filename box. + */ + void setFilenameIsEditable (const bool shouldBeEditable); - The itemId parameter can be any of the values listed by your getAllToolbarItemIds() - method, except for the built-in item types from the SpecialItemIds enum, which - are created internally by the toolbar code. + /** Sets a file or directory to be the default starting point for the browser to show. - Try not to keep a pointer to the object that is returned, as it will be deleted - automatically by the toolbar, and remember that multiple instances of the same - item type are likely to exist at the same time. + This is only used if the current file hasn't been set. */ - virtual ToolbarItemComponent* createItem (const int itemId) = 0; -}; + void setDefaultBrowseTarget (const File& newDefaultDirectory) throw(); -#endif // __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ -/********* End of inlined file: juce_ToolbarItemFactory.h *********/ + /** Returns all the entries on the recent files list. -#endif -#ifndef __JUCE_LISTBOX_JUCEHEADER__ + This can be used in conjunction with setRecentlyUsedFilenames() for saving the + state of this list. -#endif -#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ + @see setRecentlyUsedFilenames + */ + const StringArray getRecentlyUsedFilenames() const; -/********* Start of inlined file: juce_ToolbarItemPalette.h *********/ -#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ -#define __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ + /** Sets all the entries on the recent files list. -/** - A component containing a list of toolbar items, which the user can drag onto - a toolbar to add them. + This can be used in conjunction with getRecentlyUsedFilenames() for saving the + state of this list. - You can use this class directly, but it's a lot easier to call Toolbar::showCustomisationDialog(), - which automatically shows one of these in a dialog box with lots of extra controls. + @see getRecentlyUsedFilenames, addRecentlyUsedFile + */ + void setRecentlyUsedFilenames (const StringArray& filenames); - @see Toolbar -*/ -class JUCE_API ToolbarItemPalette : public Component, - public DragAndDropContainer -{ -public: + /** Adds an entry to the recently-used files dropdown list. - /** Creates a palette of items for a given factory, with the aim of adding them - to the specified toolbar. + If the file is already in the list, it will be moved to the top. A limit + is also placed on the number of items that are kept in the list. - The ToolbarItemFactory::getAllToolbarItemIds() method is used to create the - set of items that are shown in this palette. + @see getRecentlyUsedFilenames, setRecentlyUsedFilenames, setMaxNumberOfRecentFiles + */ + void addRecentlyUsedFile (const File& file); - The toolbar and factory must not be deleted while this object exists. + /** Changes the limit for the number of files that will be stored in the recent-file list. */ - ToolbarItemPalette (ToolbarItemFactory& factory, - Toolbar* const toolbar); + void setMaxNumberOfRecentFiles (const int newMaximum); - /** Destructor. */ - ~ToolbarItemPalette(); + /** Changes the text shown on the 'browse' button. + + By default this button just says "..." but you can change it. The button itself + can be changed using the look-and-feel classes, so it might not actually have any + text on it. + */ + void setBrowseButtonText (const String& browseButtonText); + + /** Adds a listener that will be called when the selected file is changed. */ + void addListener (FilenameComponentListener* const listener) throw(); + + /** Removes a previously-registered listener. */ + void removeListener (FilenameComponentListener* const listener) throw(); + + /** Gives the component a tooltip. */ + void setTooltip (const String& newTooltip); + /** @internal */ + void paintOverChildren (Graphics& g); /** @internal */ void resized(); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + bool isInterestedInFileDrag (const StringArray& files); + /** @internal */ + void filesDropped (const StringArray& files, int, int); + /** @internal */ + void fileDragEnter (const StringArray& files, int, int); + /** @internal */ + void fileDragExit (const StringArray& files); juce_UseDebuggingNewOperator private: - ToolbarItemFactory& factory; - Toolbar* toolbar; - Viewport* viewport; - - friend class Toolbar; - void replaceComponent (ToolbarItemComponent* const comp); - ToolbarItemPalette (const ToolbarItemPalette&); - const ToolbarItemPalette& operator= (const ToolbarItemPalette&); -}; + ComboBox* filenameBox; + String lastFilename; + Button* browseButton; + int maxRecentFiles; + bool isDir, isSaving, isFileDragOver; + String wildcard, enforcedSuffix, browseButtonText; + SortedSet listeners; + File defaultBrowseFile; -#endif // __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ -/********* End of inlined file: juce_ToolbarItemPalette.h *********/ + void comboBoxChanged (ComboBox*); + void buttonClicked (Button* button); + void handleAsyncUpdate(); -#endif -#ifndef __JUCE_TREEVIEW_JUCEHEADER__ + FilenameComponent (const FilenameComponent&); + const FilenameComponent& operator= (const FilenameComponent&); +}; -#endif -#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ +#endif // __JUCE_FILENAMECOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FilenameComponent.h *********/ #endif -#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ #endif -#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_BooleanPropertyComponent.h *********/ -#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_FileSearchPathListComponent.h *********/ +#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ +#define __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ /** - A PropertyComponent that contains an on/off toggle button. - - This type of property component can be used if you have a boolean value to - toggle on/off. + Shows a set of file paths in a list, allowing them to be added, removed or + re-ordered. - @see PropertyComponent + @see FileSearchPath */ -class JUCE_API BooleanPropertyComponent : public PropertyComponent, - private ButtonListener +class JUCE_API FileSearchPathListComponent : public Component, + public SettableTooltipClient, + public FileDragAndDropTarget, + private ButtonListener, + private ListBoxModel { public: - /** Creates a button component. + /** Creates an empty FileSearchPathListComponent. - @param propertyName the property name to be passed to the PropertyComponent - @param buttonTextWhenTrue the text shown in the button when the value is true - @param buttonTextWhenFalse the text shown in the button when the value is false */ - BooleanPropertyComponent (const String& propertyName, - const String& buttonTextWhenTrue, - const String& buttonTextWhenFalse); + FileSearchPathListComponent(); /** Destructor. */ - ~BooleanPropertyComponent(); + ~FileSearchPathListComponent(); - /** Called to change the state of the boolean value. */ - virtual void setState (const bool newState) = 0; + /** Returns the path as it is currently shown. */ + const FileSearchPath& getPath() const throw() { return path; } - /** Must return the current value of the property. */ - virtual bool getState() const = 0; + /** Changes the current path. */ + void setPath (const FileSearchPath& newPath); + + /** Sets a file or directory to be the default starting point for the browser to show. + + This is only used if the current file hasn't been set. + */ + void setDefaultBrowseTarget (const File& newDefaultDirectory) throw(); + + /** A set of colour IDs to use to change the colour of various aspects of the label. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1004100, /**< The background colour to fill the component with. + Make this transparent if you don't want the background to be filled. */ + }; + /** @internal */ + int getNumRows(); + /** @internal */ + void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected); + /** @internal */ + void deleteKeyPressed (int lastRowSelected); + /** @internal */ + void returnKeyPressed (int lastRowSelected); + /** @internal */ + void listBoxItemDoubleClicked (int row, const MouseEvent&); + /** @internal */ + void selectedRowsChanged (int lastRowSelected); + /** @internal */ + void resized(); /** @internal */ void paint (Graphics& g); /** @internal */ - void refresh(); + bool isInterestedInFileDrag (const StringArray& files); /** @internal */ - void buttonClicked (Button*); + void filesDropped (const StringArray& files, int, int); + /** @internal */ + void buttonClicked (Button* button); juce_UseDebuggingNewOperator private: - ToggleButton* button; - String onText, offText; + + FileSearchPath path; + File defaultBrowseTarget; + + ListBox* listBox; + Button* addButton; + Button* removeButton; + Button* changeButton; + Button* upButton; + Button* downButton; + + void changed() throw(); + void updateButtons() throw(); + + FileSearchPathListComponent (const FileSearchPathListComponent&); + const FileSearchPathListComponent& operator= (const FileSearchPathListComponent&); }; -#endif // __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_BooleanPropertyComponent.h *********/ +#endif // __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FileSearchPathListComponent.h *********/ #endif -#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ButtonPropertyComponent.h *********/ -#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_FileTreeComponent.h *********/ +#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ +#define __JUCE_FILETREECOMPONENT_JUCEHEADER__ /** - A PropertyComponent that contains a button. + A component that displays the files in a directory as a treeview. - This type of property component can be used if you need a button to trigger some - kind of action. + This implements the DirectoryContentsDisplayComponent base class so that + it can be used in a FileBrowserComponent. - @see PropertyComponent + To attach a listener to it, use its DirectoryContentsDisplayComponent base + class and the FileBrowserListener class. + + @see DirectoryContentsList, FileListComponent */ -class JUCE_API ButtonPropertyComponent : public PropertyComponent, - private ButtonListener +class JUCE_API FileTreeComponent : public TreeView, + public DirectoryContentsDisplayComponent { public: - /** Creates a button component. - - @param propertyName the property name to be passed to the PropertyComponent - @param triggerOnMouseDown this is passed to the Button::setTriggeredOnMouseDown() method + /** Creates a listbox to show the contents of a specified directory. */ - ButtonPropertyComponent (const String& propertyName, - const bool triggerOnMouseDown); + FileTreeComponent (DirectoryContentsList& listToShow); /** Destructor. */ - ~ButtonPropertyComponent(); + ~FileTreeComponent(); - /** Called when the user clicks the button. + /** Returns the number of files the user has got selected. + @see getSelectedFile */ - virtual void buttonClicked() = 0; + int getNumSelectedFiles() const { return TreeView::getNumSelectedItems(); } - /** Returns the string that should be displayed in the button. + /** Returns one of the files that the user has currently selected. + The index should be in the range 0 to (getNumSelectedFiles() - 1). + @see getNumSelectedFiles + */ + const File getSelectedFile (int index = 0) const; - If you need to change this string, call refresh() to update the component. + /** Scrolls the list to the top. */ + void scrollToTop(); + + /** Setting a name for this allows tree items to be dragged. + + The string that you pass in here will be returned by the getDragSourceDescription() + of the items in the tree. For more info, see TreeViewItem::getDragSourceDescription(). */ - virtual const String getButtonText() const = 0; + void setDragAndDropDescription (const String& description) throw(); - /** @internal */ - void refresh(); - /** @internal */ - void buttonClicked (Button*); + /** Returns the last value that was set by setDragAndDropDescription(). + */ + const String& getDragAndDropDescription() const throw() { return dragAndDropDescription; } juce_UseDebuggingNewOperator private: - TextButton* button; + String dragAndDropDescription; + + FileTreeComponent (const FileTreeComponent&); + const FileTreeComponent& operator= (const FileTreeComponent&); }; -#endif // __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ButtonPropertyComponent.h *********/ +#endif // __JUCE_FILETREECOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_FileTreeComponent.h *********/ #endif -#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ChoicePropertyComponent.h *********/ -#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_ImagePreviewComponent.h *********/ +#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ +#define __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ /** - A PropertyComponent that shows its value as a combo box. - - This type of property component contains a list of options and has a - combo box to choose one. - - Your subclass's constructor must add some strings to the choices StringArray - and these are shown in the list. - - The getIndex() method will be called to find out which option is the currently - selected one. If you call refresh() it will call getIndex() to check whether - the value has changed, and will update the combo box if needed. - - If the user selects a different item from the list, setIndex() will be - called to let your class process this. + A simple preview component that shows thumbnails of image files. - @see PropertyComponent, PropertyPanel + @see FileChooserDialogBox, FilePreviewComponent */ -class JUCE_API ChoicePropertyComponent : public PropertyComponent, - private ComboBoxListener +class JUCE_API ImagePreviewComponent : public FilePreviewComponent, + private Timer { public: - /** Creates the component. - Your subclass's constructor must add a list of options to the choices - member variable. - */ - ChoicePropertyComponent (const String& propertyName); + /** Creates an ImagePreviewComponent. */ + ImagePreviewComponent(); /** Destructor. */ - ~ChoicePropertyComponent(); - - /** Called when the user selects an item from the combo box. - - Your subclass must use this callback to update the value that this component - represents. The index is the index of the chosen item in the choices - StringArray. - */ - virtual void setIndex (const int newIndex) = 0; - - /** Returns the index of the item that should currently be shown. - - This is the index of the item in the choices StringArray that will be - shown. - */ - virtual int getIndex() const = 0; - - /** Returns the list of options. */ - const StringArray& getChoices() const throw(); + ~ImagePreviewComponent(); /** @internal */ - void refresh(); + void selectedFileChanged (const File& newSelectedFile); /** @internal */ - void comboBoxChanged (ComboBox*); + void paint (Graphics& g); + /** @internal */ + void timerCallback(); juce_UseDebuggingNewOperator -protected: - /** The list of options that will be shown in the combo box. +private: + File fileToLoad; + Image* currentThumbnail; + String currentDetails; - Your subclass must populate this array in its constructor. If any empty - strings are added, these will be replaced with horizontal separators (see - ComboBox::addSeparator() for more info). + void getThumbSize (int& w, int& h) const; + + ImagePreviewComponent (const ImagePreviewComponent&); + const ImagePreviewComponent& operator= (const ImagePreviewComponent&); +}; + +#endif // __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ImagePreviewComponent.h *********/ + +#endif +#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ + +/********* Start of inlined file: juce_WildcardFileFilter.h *********/ +#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ +#define __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ + +/** + A type of FileFilter that works by wildcard pattern matching. + + This filter only allows files that match one of the specified patterns, but + allows all directories through. + + @see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent +*/ +class JUCE_API WildcardFileFilter : public FileFilter +{ +public: + + /** + Creates a wildcard filter for one or more patterns. + + The wildcardPatterns parameter is a comma or semicolon-delimited set of + patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav + or .aiff. + + The description is a name to show the user in a list of possible patterns, so + for the wav/aiff example, your description might be "audio files". */ - StringArray choices; + WildcardFileFilter (const String& fileWildcardPatterns, + const String& directoryWildcardPatterns, + const String& description); + + /** Destructor. */ + ~WildcardFileFilter(); + + /** Returns true if the filename matches one of the patterns specified. */ + bool isFileSuitable (const File& file) const; + + /** This always returns true. */ + bool isDirectorySuitable (const File& file) const; + + juce_UseDebuggingNewOperator private: - ComboBox* comboBox; + StringArray fileWildcards, directoryWildcards; + + static void parse (const String& pattern, StringArray& result) throw(); + static bool match (const File& file, const StringArray& wildcards) throw(); }; -#endif // __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ChoicePropertyComponent.h *********/ +#endif // __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ +/********* End of inlined file: juce_WildcardFileFilter.h *********/ #endif -#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ +#ifndef __JUCE_COMPONENT_JUCEHEADER__ #endif -#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_COMPONENTDELETIONWATCHER_JUCEHEADER__ #endif -#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__ -/********* Start of inlined file: juce_SliderPropertyComponent.h *********/ -#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_DESKTOP_JUCEHEADER__ + +#endif +#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ + +#endif +#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ + +#endif +#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_KeyMappingEditorComponent.h *********/ +#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ +#define __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_KeyPressMappingSet.h *********/ +#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ +#define __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ /** - A PropertyComponent that shows its value as a slider. + Manages and edits a list of keypresses, which it uses to invoke the appropriate + command in a ApplicationCommandManager. - @see PropertyComponent, Slider + Normally, you won't actually create a KeyPressMappingSet directly, because + each ApplicationCommandManager contains its own KeyPressMappingSet, so typically + you'd create yourself an ApplicationCommandManager, and call its + ApplicationCommandManager::getKeyMappings() method to get a pointer to its + KeyPressMappingSet. + + For one of these to actually use keypresses, you'll need to add it as a KeyListener + to the top-level component for which you want to handle keystrokes. So for example: + + @code + class MyMainWindow : public Component + { + ApplicationCommandManager* myCommandManager; + + public: + MyMainWindow() + { + myCommandManager = new ApplicationCommandManager(); + + // first, make sure the command manager has registered all the commands that its + // targets can perform.. + myCommandManager->registerAllCommandsForTarget (myCommandTarget1); + myCommandManager->registerAllCommandsForTarget (myCommandTarget2); + + // this will use the command manager to initialise the KeyPressMappingSet with + // the default keypresses that were specified when the targets added their commands + // to the manager. + myCommandManager->getKeyMappings()->resetToDefaultMappings(); + + // having set up the default key-mappings, you might now want to load the last set + // of mappings that the user configured. + myCommandManager->getKeyMappings()->restoreFromXml (lastSavedKeyMappingsXML); + + // Now tell our top-level window to send any keypresses that arrive to the + // KeyPressMappingSet, which will use them to invoke the appropriate commands. + addKeyListener (myCommandManager->getKeyMappings()); + } + + ... + } + @endcode + + KeyPressMappingSet derives from ChangeBroadcaster so that interested parties can + register to be told when a command or mapping is added, removed, etc. + + There's also a UI component called KeyMappingEditorComponent that can be used + to easily edit the key mappings. + + @see Component::addKeyListener(), KeyMappingEditorComponent, ApplicationCommandManager */ -class JUCE_API SliderPropertyComponent : public PropertyComponent, - private SliderListener +class JUCE_API KeyPressMappingSet : public KeyListener, + public ChangeBroadcaster, + public FocusChangeListener { public: - /** Creates the property component. + /** Creates a KeyPressMappingSet for a given command manager. - The ranges, interval and skew factor are passed to the Slider component. + Normally, you won't actually create a KeyPressMappingSet directly, because + each ApplicationCommandManager contains its own KeyPressMappingSet, so the + best thing to do is to create your ApplicationCommandManager, and use the + ApplicationCommandManager::getKeyMappings() method to access its mappings. - If you need to customise the slider in other ways, your constructor can - access the slider member variable and change it directly. + When a suitable keypress happens, the manager's invoke() method will be + used to invoke the appropriate command. + + @see ApplicationCommandManager */ - SliderPropertyComponent (const String& propertyName, - const double rangeMin, - const double rangeMax, - const double interval, - const double skewFactor = 1.0); + KeyPressMappingSet (ApplicationCommandManager* const commandManager) throw(); + + /** Creates an copy of a KeyPressMappingSet. */ + KeyPressMappingSet (const KeyPressMappingSet& other) throw(); /** Destructor. */ - ~SliderPropertyComponent(); + ~KeyPressMappingSet(); - /** Called when the user moves the slider to change its value. + ApplicationCommandManager* getCommandManager() const throw() { return commandManager; } - Your subclass must use this method to update whatever item this property - represents. + /** Returns a list of keypresses that are assigned to a particular command. + + @param commandID the command's ID */ - virtual void setValue (const double newValue) = 0; + const Array getKeyPressesAssignedToCommand (const CommandID commandID) const throw(); - /** Returns the value that the slider should show. */ - virtual const double getValue() const = 0; + /** Assigns a keypress to a command. + + If the keypress is already assigned to a different command, it will first be + removed from that command, to avoid it triggering multiple functions. + + @param commandID the ID of the command that you want to add a keypress to. If + this is 0, the keypress will be removed from anything that it + was previously assigned to, but not re-assigned + @param newKeyPress the new key-press + @param insertIndex if this is less than zero, the key will be appended to the + end of the list of keypresses; otherwise the new keypress will + be inserted into the existing list at this index + */ + void addKeyPress (const CommandID commandID, + const KeyPress& newKeyPress, + int insertIndex = -1) throw(); + + /** Reset all mappings to the defaults, as dictated by the ApplicationCommandManager. + + @see resetToDefaultMapping + */ + void resetToDefaultMappings() throw(); + + /** Resets all key-mappings to the defaults for a particular command. + + @see resetToDefaultMappings + */ + void resetToDefaultMapping (const CommandID commandID) throw(); + + /** Removes all keypresses that are assigned to any commands. */ + void clearAllKeyPresses() throw(); + + /** Removes all keypresses that are assigned to a particular command. */ + void clearAllKeyPresses (const CommandID commandID) throw(); + + /** Removes one of the keypresses that are assigned to a command. + + See the getKeyPressesAssignedToCommand() for the list of keypresses to + which the keyPressIndex refers. + */ + void removeKeyPress (const CommandID commandID, + const int keyPressIndex) throw(); + + /** Removes a keypress from any command that it may be assigned to. + */ + void removeKeyPress (const KeyPress& keypress) throw(); + + /** Returns true if the given command is linked to this key. */ + bool containsMapping (const CommandID commandID, + const KeyPress& keyPress) const throw(); + + /** Looks for a command that corresponds to a keypress. + + @returns the UID of the command or 0 if none was found + */ + CommandID findCommandForKeyPress (const KeyPress& keyPress) const throw(); + + /** Tries to recreate the mappings from a previously stored state. + + The XML passed in must have been created by the createXml() method. + + If the stored state makes any reference to commands that aren't + currently available, these will be ignored. + + If the set of mappings being loaded was a set of differences (using createXml (true)), + then this will call resetToDefaultMappings() and then merge the saved mappings + on top. If the saved set was created with createXml (false), then this method + will first clear all existing mappings and load the saved ones as a complete set. + + @returns true if it manages to load the XML correctly + @see createXml + */ + bool restoreFromXml (const XmlElement& xmlVersion); + + /** Creates an XML representation of the current mappings. + + This will produce a lump of XML that can be later reloaded using + restoreFromXml() to recreate the current mapping state. + + The object that is returned must be deleted by the caller. + + @param saveDifferencesFromDefaultSet if this is false, then all keypresses + will be saved into the XML. If it's true, then the XML will + only store the differences between the current mappings and + the default mappings you'd get from calling resetToDefaultMappings(). + The advantage of saving a set of differences from the default is that + if you change the default mappings (in a new version of your app, for + example), then these will be merged into a user's saved preferences. + + @see restoreFromXml + */ + XmlElement* createXml (const bool saveDifferencesFromDefaultSet) const; /** @internal */ - void refresh(); + bool keyPressed (const KeyPress& key, Component* originatingComponent); /** @internal */ - void changeListenerCallback (void*); + bool keyStateChanged (const bool isKeyDown, Component* originatingComponent); /** @internal */ - void sliderValueChanged (Slider*); + void globalFocusChanged (Component* focusedComponent); juce_UseDebuggingNewOperator -protected: +private: - /** The slider component being used in this component. + ApplicationCommandManager* commandManager; - Your subclass has access to this in case it needs to customise it in some way. - */ - Slider* slider; -}; + struct CommandMapping + { + CommandID commandID; + Array keypresses; + bool wantsKeyUpDownCallbacks; + }; -#endif // __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_SliderPropertyComponent.h *********/ + OwnedArray mappings; -#endif -#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ + struct KeyPressTime + { + KeyPress key; + uint32 timeWhenPressed; + }; -/********* Start of inlined file: juce_TextPropertyComponent.h *********/ -#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ -#define __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ + OwnedArray keysDown; + + void handleMessage (const Message& message); + + void invokeCommand (const CommandID commandID, + const KeyPress& keyPress, + const bool isKeyDown, + const int millisecsSinceKeyPressed, + Component* const originatingComponent) const; + + const KeyPressMappingSet& operator= (const KeyPressMappingSet&); +}; + +#endif // __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ +/********* End of inlined file: juce_KeyPressMappingSet.h *********/ /** - A PropertyComponent that shows its value as editable text. + A component to allow editing of the keymaps stored by a KeyPressMappingSet + object. - @see PropertyComponent + @see KeyPressMappingSet */ -class JUCE_API TextPropertyComponent : public PropertyComponent +class JUCE_API KeyMappingEditorComponent : public Component, + public TreeViewItem, + public ChangeListener, + private ButtonListener { public: - /** Creates a text property component. - - The maxNumChars is used to set the length of string allowable, and isMultiLine - sets whether the text editor allows carriage returns. + /** Creates a KeyMappingEditorComponent. - @see TextEditor + @param mappingSet this is the set of mappings to display and + edit. Make sure the mappings object is not + deleted before this component! + @param showResetToDefaultButton if true, then at the bottom of the + list, the component will include a 'reset to + defaults' button. */ - TextPropertyComponent (const String& propertyName, - const int maxNumChars, - const bool isMultiLine); + KeyMappingEditorComponent (KeyPressMappingSet* const mappingSet, + const bool showResetToDefaultButton); /** Destructor. */ - ~TextPropertyComponent(); + virtual ~KeyMappingEditorComponent(); - /** Called when the user edits the text. + /** Sets up the colours to use for parts of the component. - Your subclass must use this callback to change the value of whatever item - this property component represents. + @param mainBackground colour to use for most of the background + @param textColour colour to use for the text */ - virtual void setText (const String& newText) = 0; + void setColours (const Colour& mainBackground, + const Colour& textColour); - /** Returns the text that should be shown in the text editor. + /** Returns the KeyPressMappingSet that this component is acting upon. */ - virtual const String getText() const = 0; + KeyPressMappingSet* getMappings() const throw() { return mappings; } + + /** Can be overridden if some commands need to be excluded from the list. + + By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor() + method to decide what to return, but you can override it to handle special cases. + */ + virtual bool shouldCommandBeIncluded (const CommandID commandID); + + /** Can be overridden to indicate that some commands are shown as read-only. + + By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor() + method to decide what to return, but you can override it to handle special cases. + */ + virtual bool isCommandReadOnly (const CommandID commandID); + + /** This can be overridden to let you change the format of the string used + to describe a keypress. + + This is handy if you're using non-standard KeyPress objects, e.g. for custom + keys that are triggered by something else externally. If you override the + method, be sure to let the base class's method handle keys you're not + interested in. + */ + virtual const String getDescriptionForKeyPress (const KeyPress& key); + + /** A set of colour IDs to use to change the colour of various aspects of the editor. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + To change the colours of the menu that pops up + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x100ad00, /**< The background colour to fill the editor background. */ + textColourId = 0x100ad01, /**< The colour for the text. */ + }; /** @internal */ - void refresh(); + void parentHierarchyChanged(); /** @internal */ - void textWasEdited(); + void resized(); + /** @internal */ + void changeListenerCallback (void*); + /** @internal */ + bool mightContainSubItems(); + /** @internal */ + const String getUniqueName() const; + /** @internal */ + void buttonClicked (Button* button); juce_UseDebuggingNewOperator private: - Label* textEditor; + + KeyPressMappingSet* mappings; + TreeView* tree; + friend class KeyMappingTreeViewItem; + friend class KeyCategoryTreeViewItem; + friend class KeyMappingItemComponent; + friend class KeyMappingChangeButton; + TextButton* resetButton; + + void assignNewKey (const CommandID commandID, int index); + + KeyMappingEditorComponent (const KeyMappingEditorComponent&); + const KeyMappingEditorComponent& operator= (const KeyMappingEditorComponent&); }; -#endif // __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_TextPropertyComponent.h *********/ +#endif // __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_KeyMappingEditorComponent.h *********/ + +#endif +#ifndef __JUCE_KEYPRESS_JUCEHEADER__ + +#endif +#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ + +#endif +#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ #endif #ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ @@ -49384,291 +48709,203 @@ private: #ifndef __JUCE_DOCUMENTWINDOW_JUCEHEADER__ #define __JUCE_DOCUMENTWINDOW_JUCEHEADER__ -/********* Start of inlined file: juce_ResizableWindow.h *********/ -#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__ -#define __JUCE_RESIZABLEWINDOW_JUCEHEADER__ +/********* Start of inlined file: juce_MenuBarComponent.h *********/ +#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__ +#define __JUCE_MENUBARCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_TopLevelWindow.h *********/ -#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__ -#define __JUCE_TOPLEVELWINDOW_JUCEHEADER__ +/********* Start of inlined file: juce_MenuBarModel.h *********/ +#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__ +#define __JUCE_MENUBARMODEL_JUCEHEADER__ -/********* Start of inlined file: juce_DropShadower.h *********/ -#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ -#define __JUCE_DROPSHADOWER_JUCEHEADER__ +class MenuBarModel; /** - Adds a drop-shadow to a component. - - This object creates and manages a set of components which sit around a - component, creating a gaussian shadow around it. The components will track - the position of the component and if it's brought to the front they'll also - follow this. + A class to receive callbacks when a MenuBarModel changes. - For desktop windows you don't need to use this class directly - just - set the Component::windowHasDropShadow flag when calling - Component::addToDesktop(), and the system will create one of these if it's - needed (which it obviously isn't on the Mac, for example). + @see MenuBarModel::addListener, MenuBarModel::removeListener, MenuBarModel::menuItemsChanged */ -class JUCE_API DropShadower : public ComponentListener +class JUCE_API MenuBarModelListener { public: + /** Destructor. */ + virtual ~MenuBarModelListener() {} - /** Creates a DropShadower. + /** This callback is made when items are changed in the menu bar model. + */ + virtual void menuBarItemsChanged (MenuBarModel* menuBarModel) = 0; - @param alpha the opacity of the shadows, from 0 to 1.0 - @param xOffset the horizontal displacement of the shadow, in pixels - @param yOffset the vertical displacement of the shadow, in pixels - @param blurRadius the radius of the blur to use for creating the shadow + /** This callback is made when an application command is invoked that + is represented by one of the items in the menu bar model. */ - DropShadower (const float alpha = 0.5f, - const int xOffset = 1, - const int yOffset = 5, - const float blurRadius = 10.0f); + virtual void menuCommandInvoked (MenuBarModel* menuBarModel, + const ApplicationCommandTarget::InvocationInfo& info) = 0; +}; + +/** + A class for controlling MenuBar components. + + This class is used to tell a MenuBar what menus to show, and to respond + to a menu being selected. + + @see MenuBarModelListener, MenuBarComponent, PopupMenu +*/ +class JUCE_API MenuBarModel : private AsyncUpdater, + private ApplicationCommandManagerListener +{ +public: + + MenuBarModel() throw(); /** Destructor. */ - virtual ~DropShadower(); + virtual ~MenuBarModel(); - /** Attaches the DropShadower to the component you want to shadow. */ - void setOwner (Component* componentToFollow); + /** Call this when some of your menu items have changed. - /** @internal */ - void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); - /** @internal */ - void componentBroughtToFront (Component& component); - /** @internal */ - void componentChildrenChanged (Component& component); - /** @internal */ - void componentParentHierarchyChanged (Component& component); - /** @internal */ - void componentVisibilityChanged (Component& component); - - juce_UseDebuggingNewOperator - -private: - - Component* owner; - int numShadows; - Component* shadowWindows[4]; - Image* shadowImageSections[12]; - const int shadowEdge, xOffset, yOffset; - const float alpha, blurRadius; - bool inDestructor, reentrant; - - void updateShadows(); - void setShadowImage (Image* const src, - const int num, - const int w, const int h, - const int sx, const int sy) throw(); - - void bringShadowWindowsToFront(); - void deleteShadowWindows(); - - DropShadower (const DropShadower&); - const DropShadower& operator= (const DropShadower&); -}; - -#endif // __JUCE_DROPSHADOWER_JUCEHEADER__ -/********* End of inlined file: juce_DropShadower.h *********/ - -/** - A base class for top-level windows. - - This class is used for components that are considered a major part of your - application - e.g. ResizableWindow, DocumentWindow, DialogWindow, AlertWindow, - etc. Things like menus that pop up briefly aren't derived from it. - - A TopLevelWindow is probably on the desktop, but this isn't mandatory - it - could itself be the child of another component. - - The class manages a list of all instances of top-level windows that are in use, - and each one is also given the concept of being "active". The active window is - one that is actively being used by the user. This isn't quite the same as the - component with the keyboard focus, because there may be a popup menu or other - temporary window which gets keyboard focus while the active top level window is - unchanged. + This method will cause a callback to any MenuBarListener objects that + are registered with this model. - A top-level window also has an optional drop-shadow. + If this model is displaying items from an ApplicationCommandManager, you + can use the setApplicationCommandManagerToWatch() method to cause + change messages to be sent automatically when the ApplicationCommandManager + is changed. - @see ResizableWindow, DocumentWindow, DialogWindow -*/ -class JUCE_API TopLevelWindow : public Component -{ -public: + @see addListener, removeListener, MenuBarListener + */ + void menuItemsChanged(); - /** Creates a TopLevelWindow. + /** Tells the menu bar to listen to the specified command manager, and to update + itself when the commands change. - @param name the name to give the component - @param addToDesktop if true, the window will be automatically added to the - desktop; if false, you can use it as a child component + This will also allow it to flash a menu name when a command from that menu + is invoked using a keystroke. */ - TopLevelWindow (const String& name, - const bool addToDesktop); - - /** Destructor. */ - ~TopLevelWindow(); + void setApplicationCommandManagerToWatch (ApplicationCommandManager* const manager) throw(); - /** True if this is currently the TopLevelWindow that is actively being used. + /** Registers a listener for callbacks when the menu items in this model change. - This isn't quite the same as having keyboard focus, because the focus may be - on a child component or a temporary pop-up menu, etc, while this window is - still considered to be active. + The listener object will get callbacks when this object's menuItemsChanged() + method is called. - @see activeWindowStatusChanged + @see removeListener */ - bool isActiveWindow() const throw() { return windowIsActive_; } - - /** This will set the bounds of the window so that it's centred in front of another - window. + void addListener (MenuBarModelListener* const listenerToAdd) throw(); - If your app has a few windows open and want to pop up a dialog box for one of - them, you can use this to show it in front of the relevent parent window, which - is a bit neater than just having it appear in the middle of the screen. + /** Removes a listener. - If componentToCentreAround is 0, then the currently active TopLevelWindow will - be used instead. If no window is focused, it'll just default to the middle of the - screen. + @see addListener */ - void centreAroundComponent (Component* componentToCentreAround, - const int width, const int height); + void removeListener (MenuBarModelListener* const listenerToRemove) throw(); - /** Turns the drop-shadow on and off. */ - void setDropShadowEnabled (const bool useShadow); + /** This method must return a list of the names of the menus. */ + virtual const StringArray getMenuBarNames() = 0; - /** Sets whether an OS-native title bar will be used, or a Juce one. + /** This should return the popup menu to display for a given top-level menu. - @see isUsingNativeTitleBar + @param topLevelMenuIndex the index of the top-level menu to show + @param menuName the name of the top-level menu item to show */ - void setUsingNativeTitleBar (const bool useNativeTitleBar); + virtual const PopupMenu getMenuForIndex (int topLevelMenuIndex, + const String& menuName) = 0; - /** Returns true if the window is currently using an OS-native title bar. + /** This is called when a menu item has been clicked on. - @see setUsingNativeTitleBar + @param menuItemID the item ID of the PopupMenu item that was selected + @param topLevelMenuIndex the index of the top-level menu from which the item was + chosen (just in case you've used duplicate ID numbers + on more than one of the popup menus) */ - bool isUsingNativeTitleBar() const throw() { return useNativeTitleBar && isOnDesktop(); } - - /** Returns the number of TopLevelWindow objects currently in use. + virtual void menuItemSelected (int menuItemID, + int topLevelMenuIndex) = 0; - @see getTopLevelWindow - */ - static int getNumTopLevelWindows() throw(); +#if JUCE_MAC || DOXYGEN + /** MAC ONLY - Sets the model that is currently being shown as the main + menu bar at the top of the screen on the Mac. - /** Returns one of the TopLevelWindow objects currently in use. + You can pass 0 to stop the current model being displayed. Be careful + not to delete a model while it is being used. - The index is 0 to (getNumTopLevelWindows() - 1). + An optional extra menu can be specified, containing items to add to the top of + the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of + an apple, it's the one next to it, with your application's name at the top + and the services menu etc on it). When one of these items is selected, the + menu bar model will be used to invoke it, and in the menuItemSelected() callback + the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems + object then newMenuBarModel must be non-null. */ - static TopLevelWindow* getTopLevelWindow (const int index) throw(); - - /** Returns the currently-active top level window. + static void setMacMainMenu (MenuBarModel* newMenuBarModel, + const PopupMenu* extraAppleMenuItems = 0) throw(); - There might not be one, of course, so this can return 0. + /** MAC ONLY - Returns the menu model that is currently being shown as + the main menu bar. */ - static TopLevelWindow* getActiveTopLevelWindow() throw(); - - juce_UseDebuggingNewOperator - - /** @internal */ - virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = 0); - -protected: - - /** This callback happens when this window becomes active or inactive. + static MenuBarModel* getMacMainMenu() throw(); - @see isActiveWindow - */ - virtual void activeWindowStatusChanged(); +#endif /** @internal */ - void focusOfChildComponentChanged (FocusChangeType cause); - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - void visibilityChanged(); + void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info); /** @internal */ - virtual int getDesktopWindowStyleFlags() const; + void applicationCommandListChanged(); /** @internal */ - void recreateDesktopWindow(); + void handleAsyncUpdate(); -private: - friend class TopLevelWindowManager; - bool useDropShadow, useNativeTitleBar, windowIsActive_; - DropShadower* shadower; + juce_UseDebuggingNewOperator - void setWindowActive (const bool isNowActive) throw(); +private: + ApplicationCommandManager* manager; + SortedSet listeners; - TopLevelWindow (const TopLevelWindow&); - const TopLevelWindow& operator= (const TopLevelWindow&); + MenuBarModel (const MenuBarModel&); + const MenuBarModel& operator= (const MenuBarModel&); }; -#endif // __JUCE_TOPLEVELWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_TopLevelWindow.h *********/ - -/********* Start of inlined file: juce_ResizableBorderComponent.h *********/ -#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ -#define __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ +#endif // __JUCE_MENUBARMODEL_JUCEHEADER__ +/********* End of inlined file: juce_MenuBarModel.h *********/ /** - A component that resizes its parent window when dragged. - - This component forms a frame around the edge of a component, allowing it to - be dragged by the edges or corners to resize it - like the way windows are - resized in MSWindows or Linux. - - To use it, just add it to your component, making it fill the entire parent component - (there's a mouse hit-test that only traps mouse-events which land around the - edge of the component, so it's even ok to put it on top of any other components - you're using). Make sure you rescale the resizer component to fill the parent - each time the parent's size changes. + A menu bar component. - @see ResizableCornerComponent + @see MenuBarModel */ -class JUCE_API ResizableBorderComponent : public Component +class JUCE_API MenuBarComponent : public Component, + private MenuBarModelListener, + private Timer { public: - /** Creates a resizer. - - Pass in the target component which you want to be resized when this one is - dragged. - - The target component will usually be a parent of the resizer component, but this - isn't mandatory. - - Remember that when the target component is resized, it'll need to move and - resize this component to keep it in place, as this won't happen automatically. - - If the constrainer parameter is non-zero, then this object will be used to enforce - limits on the size and position that the component can be stretched to. Make sure - that the constrainer isn't deleted while still in use by this object. + /** Creates a menu bar. - @see ComponentBoundsConstrainer + @param model the model object to use to control this bar. You can + pass 0 into this if you like, and set the model later + using the setModel() method */ - ResizableBorderComponent (Component* const componentToResize, - ComponentBoundsConstrainer* const constrainer); + MenuBarComponent (MenuBarModel* const model); /** Destructor. */ - ~ResizableBorderComponent(); + ~MenuBarComponent(); - /** Specifies how many pixels wide the draggable edges of this component are. + /** Changes the model object to use to control the bar. - @see getBorderThickness + This can be 0, in which case the bar will be empty. Don't delete the object + that is passed-in while it's still being used by this MenuBar. */ - void setBorderThickness (const BorderSize& newBorderSize) throw(); + void setModel (MenuBarModel* const newModel); - /** Returns the number of pixels wide that the draggable edges of this component are. + /** Pops up one of the menu items. - @see setBorderThickness + This lets you manually open one of the menus - it could be triggered by a + key shortcut, for example. */ - const BorderSize getBorderThickness() const throw(); - - juce_UseDebuggingNewOperator + void showMenu (const int menuIndex); -protected: /** @internal */ void paint (Graphics& g); /** @internal */ + void resized(); + /** @internal */ void mouseEnter (const MouseEvent& e); /** @internal */ - void mouseMove (const MouseEvent& e); + void mouseExit (const MouseEvent& e); /** @internal */ void mouseDown (const MouseEvent& e); /** @internal */ @@ -49676,319 +48913,211 @@ protected: /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ - bool hitTest (int x, int y); - -private: - Component* const component; - ComponentBoundsConstrainer* constrainer; - BorderSize borderSize; - int originalX, originalY, originalW, originalH; - int mouseZone; - - void updateMouseZone (const MouseEvent& e) throw(); - - ResizableBorderComponent (const ResizableBorderComponent&); - const ResizableBorderComponent& operator= (const ResizableBorderComponent&); -}; - -#endif // __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ResizableBorderComponent.h *********/ - -/********* Start of inlined file: juce_ResizableCornerComponent.h *********/ -#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ -#define __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ - -/** A component that resizes a parent window when dragged. - - This is the small triangular stripey resizer component you get in the bottom-right - of windows (more commonly on the Mac than Windows). Put one in the corner of - a larger component and it will automatically resize its parent when it gets dragged - around. - - @see ResizableFrameComponent -*/ -class JUCE_API ResizableCornerComponent : public Component -{ -public: - - /** Creates a resizer. - - Pass in the target component which you want to be resized when this one is - dragged. - - The target component will usually be a parent of the resizer component, but this - isn't mandatory. - - Remember that when the target component is resized, it'll need to move and - resize this component to keep it in place, as this won't happen automatically. - - If the constrainer parameter is non-zero, then this object will be used to enforce - limits on the size and position that the component can be stretched to. Make sure - that the constrainer isn't deleted while still in use by this object. If you - pass a zero in here, no limits will be put on the sizes it can be stretched to. - - @see ComponentBoundsConstrainer - */ - ResizableCornerComponent (Component* const componentToResize, - ComponentBoundsConstrainer* const constrainer); - - /** Destructor. */ - ~ResizableCornerComponent(); - - juce_UseDebuggingNewOperator - -protected: + void mouseMove (const MouseEvent& e); /** @internal */ - void paint (Graphics& g); + void inputAttemptWhenModal(); /** @internal */ - void mouseDown (const MouseEvent& e); + void handleCommandMessage (int commandId); /** @internal */ - void mouseDrag (const MouseEvent& e); + bool keyPressed (const KeyPress& key); /** @internal */ - void mouseUp (const MouseEvent& e); + void menuBarItemsChanged (MenuBarModel* menuBarModel); /** @internal */ - bool hitTest (int x, int y); + void menuCommandInvoked (MenuBarModel* menuBarModel, + const ApplicationCommandTarget::InvocationInfo& info); + + juce_UseDebuggingNewOperator private: + MenuBarModel* model; - Component* const component; - ComponentBoundsConstrainer* constrainer; - int originalX, originalY, originalW, originalH; + StringArray menuNames; + Array xPositions; + int itemUnderMouse, currentPopupIndex, topLevelIndexClicked, indexToShowAgain; + int lastMouseX, lastMouseY; + bool inModalState; + Component* currentPopup; - ResizableCornerComponent (const ResizableCornerComponent&); - const ResizableCornerComponent& operator= (const ResizableCornerComponent&); + int getItemAt (int x, int y); + void updateItemUnderMouse (const int x, const int y); + void hideCurrentMenu(); + void timerCallback(); + void repaintMenuItem (int index); + + MenuBarComponent (const MenuBarComponent&); + const MenuBarComponent& operator= (const MenuBarComponent&); }; -#endif // __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ResizableCornerComponent.h *********/ +#endif // __JUCE_MENUBARCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_MenuBarComponent.h *********/ /** - A base class for top-level windows that can be dragged around and resized. + A resizable window with a title bar and maximise, minimise and close buttons. - To add content to the window, use its setContentComponent() method to - give it a component that will remain positioned inside it (leaving a gap around - the edges for a border). + This subclass of ResizableWindow creates a fairly standard type of window with + a title bar and various buttons. The name of the component is shown in the + title bar, and an icon can optionally be specified with setIcon(). - It's not advisable to add child components directly to a ResizableWindow: put them + All the methods available to a ResizableWindow are also available to this, + so it can easily be made resizable, minimised, maximised, etc. + + It's not advisable to add child components directly to a DocumentWindow: put them inside your content component instead. And overriding methods like resized(), moved(), etc is also not recommended - instead override these methods for your content component. (If for some obscure reason you do need to override these methods, always remember to call the super-class's resized() method too, otherwise it'll fail to lay out the window decorations correctly). - By default resizing isn't enabled - use the setResizable() method to enable it and - to choose the style of resizing to use. + You can also automatically add a menu bar to the window, using the setMenuBar() + method. - @see TopLevelWindow + @see ResizableWindow, DialogWindow */ -class JUCE_API ResizableWindow : public TopLevelWindow +class JUCE_API DocumentWindow : public ResizableWindow { public: - /** Creates a ResizableWindow. - - This constructor doesn't specify a background colour, so the LookAndFeel's default - background colour will be used. + /** The set of available button-types that can be put on the title bar. - @param name the name to give the component - @param addToDesktop if true, the window will be automatically added to the - desktop; if false, you can use it as a child component + @see setTitleBarButtonsRequired */ - ResizableWindow (const String& name, - const bool addToDesktop); + enum TitleBarButtons + { + minimiseButton = 1, + maximiseButton = 2, + closeButton = 4, - /** Creates a ResizableWindow. + /** A combination of all the buttons above. */ + allButtons = 7 + }; - @param name the name to give the component - @param backgroundColour the colour to use for filling the window's background. - @param addToDesktop if true, the window will be automatically added to the - desktop; if false, you can use it as a child component + /** Creates a DocumentWindow. + + @param name the name to give the component - this is also + the title shown at the top of the window. To change + this later, use setName() + @param backgroundColour the colour to use for filling the window's background. + @param requiredButtons specifies which of the buttons (close, minimise, maximise) + should be shown on the title bar. This value is a bitwise + combination of values from the TitleBarButtons enum. Note + that it can be "allButtons" to get them all. You + can change this later with the setTitleBarButtonsRequired() + method, which can also specify where they are positioned. + @param addToDesktop if true, the window will be automatically added to the + desktop; if false, you can use it as a child component + @see TitleBarButtons */ - ResizableWindow (const String& name, - const Colour& backgroundColour, - const bool addToDesktop); + DocumentWindow (const String& name, + const Colour& backgroundColour, + const int requiredButtons, + const bool addToDesktop = true); /** Destructor. If a content component has been set with setContentComponent(), it will be deleted. */ - ~ResizableWindow(); + ~DocumentWindow(); - /** Returns the colour currently being used for the window's background. + /** Changes the component's name. - As a convenience the window will fill itself with this colour, but you - can override the paint() method if you need more customised behaviour. + (This is overridden from Component::setName() to cause a repaint, as + the name is what gets drawn across the window's title bar). + */ + void setName (const String& newName); - This method is the same as retrieving the colour for ResizableWindow::backgroundColourId. + /** Sets an icon to show in the title bar, next to the title. - @see setBackgroundColour + A copy is made internally of the image, so the caller can delete the + image after calling this. If 0 is passed-in, any existing icon will be + removed. */ - const Colour getBackgroundColour() const throw(); - - /** Changes the colour currently being used for the window's background. + void setIcon (const Image* imageToUse); - As a convenience the window will fill itself with this colour, but you - can override the paint() method if you need more customised behaviour. + /** Changes the height of the title-bar. */ + void setTitleBarHeight (const int newHeight); - Note that the opaque state of this window is altered by this call to reflect - the opacity of the colour passed-in. On window systems which can't support - semi-transparent windows this might cause problems, (though it's unlikely you'll - be using this class as a base for a semi-transparent component anyway). + /** Returns the current title bar height. */ + int getTitleBarHeight() const; - You can also use the ResizableWindow::backgroundColourId colour id to set - this colour. + /** Changes the set of title-bar buttons being shown. - @see getBackgroundColour + @param requiredButtons specifies which of the buttons (close, minimise, maximise) + should be shown on the title bar. This value is a bitwise + combination of values from the TitleBarButtons enum. Note + that it can be "allButtons" to get them all. + @param positionTitleBarButtonsOnLeft if true, the buttons should go at the + left side of the bar; if false, they'll be placed at the right */ - void setBackgroundColour (const Colour& newColour); + void setTitleBarButtonsRequired (const int requiredButtons, + const bool positionTitleBarButtonsOnLeft); - /** Make the window resizable or fixed. + /** Sets whether the title should be centred within the window. - @param shouldBeResizable whether it's resizable at all - @param useBottomRightCornerResizer if true, it'll add a ResizableCornerComponent at the - bottom-right; if false, it'll use a ResizableBorderComponent - around the edge - @see setResizeLimits, isResizable + If true, the title text is shown in the middle of the title-bar; if false, + it'll be shown at the left of the bar. */ - void setResizable (const bool shouldBeResizable, - const bool useBottomRightCornerResizer); + void setTitleBarTextCentred (const bool textShouldBeCentred); - /** True if resizing is enabled. + /** Creates a menu inside this window. - @see setResizable + @param menuBarModel this specifies a MenuBarModel that should be used to + generate the contents of a menu bar that will be placed + just below the title bar, and just above any content + component. If this value is zero, any existing menu bar + will be removed from the component; if non-zero, one will + be added if it's required. + @param menuBarHeight the height of the menu bar component, if one is needed. Pass a value of zero + or less to use the look-and-feel's default size. */ - bool isResizable() const throw(); - - /** This sets the maximum and minimum sizes for the window. + void setMenuBar (MenuBarModel* menuBarModel, + const int menuBarHeight = 0); - If the window's current size is outside these limits, it will be resized to - make sure it's within them. + /** This method is called when the user tries to close the window. - Calling setBounds() on the component will bypass any size checking - it's only when - the window is being resized by the user that these values are enforced. + This is triggered by the user clicking the close button, or using some other + OS-specific key shortcut or OS menu for getting rid of a window. - @see setResizable, setFixedAspectRatio - */ - void setResizeLimits (const int newMinimumWidth, - const int newMinimumHeight, - const int newMaximumWidth, - const int newMaximumHeight) throw(); - - /** Returns the bounds constrainer object that this window is using. - - You can access this to change its properties. - */ - ComponentBoundsConstrainer* getConstrainer() throw() { return constrainer; } - - /** Sets the bounds-constrainer object to use for resizing and dragging this window. - - A pointer to the object you pass in will be kept, but it won't be deleted - by this object, so it's the caller's responsiblity to manage it. - - If you pass 0, then no contraints will be placed on the positioning of the window. - */ - void setConstrainer (ComponentBoundsConstrainer* newConstrainer); - - /** Calls the window's setBounds method, after first checking these bounds - with the current constrainer. - - @see setConstrainer - */ - void setBoundsConstrained (int x, int y, int width, int height); - - /** Returns true if the window is currently in full-screen mode. - - @see setFullScreen - */ - bool isFullScreen() const; - - /** Puts the window into full-screen mode, or restores it to its normal size. - - If true, the window will become full-screen; if false, it will return to the - last size it was before being made full-screen. - - @see isFullScreen - */ - void setFullScreen (const bool shouldBeFullScreen); - - /** Returns true if the window is currently minimised. - - @see setMinimised - */ - bool isMinimised() const; - - /** Minimises the window, or restores it to its previous position and size. - - When being un-minimised, it'll return to the last position and size it - was in before being minimised. - - @see isMinimised - */ - void setMinimised (const bool shouldMinimise); - - /** Returns a string which encodes the window's current size and position. - - This string will encapsulate the window's size, position, and whether it's - in full-screen mode. It's intended for letting your application save and - restore a window's position. + If the window is just a pop-up, you should override this closeButtonPressed() + method and make it delete the window in whatever way is appropriate for your + app. E.g. you might just want to call "delete this". - Use the restoreWindowStateFromString() to restore from a saved state. + If your app is centred around this window such that the whole app should quit when + the window is closed, then you will probably want to use this method as an opportunity + to call JUCEApplication::quit(), and leave the window to be deleted later by your + JUCEApplication::shutdown() method. (Doing it this way means that your window will + still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac + or closing it via the taskbar icon on Windows). - @see restoreWindowStateFromString + (Note that the DocumentWindow class overrides Component::userTriedToCloseWindow() and + redirects it to call this method, so any methods of closing the window that are + caught by userTriedToCloseWindow() will also end up here). */ - const String getWindowStateAsString(); - - /** Restores the window to a previously-saved size and position. + virtual void closeButtonPressed(); - This restores the window's size, positon and full-screen status from an - string that was previously created with the getWindowStateAsString() - method. + /** Callback that is triggered when the minimise button is pressed. - @returns false if the string wasn't a valid window state - @see getWindowStateAsString + The default implementation of this calls ResizableWindow::setMinimised(), but + you can override it to do more customised behaviour. */ - bool restoreWindowStateFromString (const String& previousState); - - /** Returns the current content component. + virtual void minimiseButtonPressed(); - This will be the component set by setContentComponent(), or 0 if none - has yet been specified. + /** Callback that is triggered when the maximise button is pressed, or when the + title-bar is double-clicked. - @see setContentComponent + The default implementation of this calls ResizableWindow::setFullScreen(), but + you can override it to do more customised behaviour. */ - Component* getContentComponent() const throw() { return contentComponent; } - - /** Changes the current content component. - - This sets a component that will be placed in the centre of the ResizableWindow, - (leaving a space around the edge for the border). - - You should never add components directly to a ResizableWindow (or any of its subclasses) - with addChildComponent(). Instead, add them to the content component. + virtual void maximiseButtonPressed(); - @param newContentComponent the new component to use (or null to not use one) - this - component will be deleted either when replaced by another call - to this method, or when the ResizableWindow is deleted. - To remove a content component without deleting it, use - setContentComponent (0, false). - @param deleteOldOne if true, the previous content component will be deleted; if - false, the previous component will just be removed without - deleting it. - @param resizeToFit if true, the ResizableWindow will maintain its size such that - it always fits around the size of the content component. If false, the - new content will be resized to fit the current space available. - */ - void setContentComponent (Component* const newContentComponent, - const bool deleteOldOne = true, - const bool resizeToFit = false); + /** Returns the close button, (or 0 if there isn't one). */ + Button* getCloseButton() const throw(); - /** Changes the window so that the content component ends up with the specified size. + /** Returns the minimise button, (or 0 if there isn't one). */ + Button* getMinimiseButton() const throw(); - This is basically a setSize call on the window, but which adds on the borders, - so you can specify the content component's target size. - */ - void setContentComponentSize (int width, int height); + /** Returns the maximise button, (or 0 if there isn't one). */ + Button* getMaximiseButton() const throw(); /** A set of colour IDs to use to change the colour of various aspects of the window. @@ -49999,5807 +49128,6950 @@ public: */ enum ColourIds { - backgroundColourId = 0x1005700, /**< A colour to use to fill the window's background. */ + textColourId = 0x1005701, /**< The colour to draw any text with. It's up to the look + and feel class how this is used. */ }; - juce_UseDebuggingNewOperator - -protected: /** @internal */ void paint (Graphics& g); - /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ - void moved(); - /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */ - void resized(); - /** @internal */ - void mouseDown (const MouseEvent& e); /** @internal */ - void mouseDrag (const MouseEvent& e); + void resized(); /** @internal */ void lookAndFeelChanged(); /** @internal */ - void childBoundsChanged (Component* child); + const BorderSize getBorderThickness(); /** @internal */ - void parentSizeChanged(); + const BorderSize getContentComponentBorder(); /** @internal */ - void visibilityChanged(); + void mouseDoubleClick (const MouseEvent& e); + /** @internal */ + void userTriedToCloseWindow(); /** @internal */ void activeWindowStatusChanged(); /** @internal */ int getDesktopWindowStyleFlags() const; + /** @internal */ + void parentHierarchyChanged(); + /** @internal */ + const Rectangle getTitleBarArea(); - /** Returns the width of the border to use around the window. + juce_UseDebuggingNewOperator - @see getContentComponentBorder - */ - virtual const BorderSize getBorderThickness(); +private: + int titleBarHeight, menuBarHeight, requiredButtons; + bool positionTitleBarButtonsOnLeft, drawTitleTextCentred; + Button* titleBarButtons [3]; + Image* titleBarIcon; + MenuBarComponent* menuBar; + MenuBarModel* menuBarModel; - /** Returns the insets to use when positioning the content component. + class ButtonListenerProxy : public ButtonListener + { + public: + ButtonListenerProxy(); + void buttonClicked (Button* button); - @see getBorderThickness - */ - virtual const BorderSize getContentComponentBorder(); + DocumentWindow* owner; -#ifdef JUCE_DEBUG - /** Overridden to warn people about adding components directly to this component - instead of using setContentComponent(). + } buttonListener; - If you know what you're doing and are sure you really want to add a component, specify - a base-class method call to Component::addAndMakeVisible(), to side-step this warning. - */ - void addChildComponent (Component* const child, int zOrder = -1); - /** Overridden to warn people about adding components directly to this component - instead of using setContentComponent(). + void repaintTitleBar(); - If you know what you're doing and are sure you really want to add a component, specify - a base-class method call to Component::addAndMakeVisible(), to side-step this warning. - */ - void addAndMakeVisible (Component* const child, int zOrder = -1); + DocumentWindow (const DocumentWindow&); + const DocumentWindow& operator= (const DocumentWindow&); +}; -#endif +#endif // __JUCE_DOCUMENTWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_DocumentWindow.h *********/ - ResizableCornerComponent* resizableCorner; - ResizableBorderComponent* resizableBorder; +class MultiDocumentPanel; +class MDITabbedComponentInternal; -private: - Component* contentComponent; - bool resizeToFitContent, fullscreen; - ComponentDragger dragger; - Rectangle lastNonFullScreenPos; - ComponentBoundsConstrainer defaultConstrainer; - ComponentBoundsConstrainer* constrainer; - #ifdef JUCE_DEBUG - bool hasBeenResized; - #endif +/** + This is a derivative of DocumentWindow that is used inside a MultiDocumentPanel + component. - void updateLastPos(); + It's like a normal DocumentWindow but has some extra functionality to make sure + everything works nicely inside a MultiDocumentPanel. - ResizableWindow (const ResizableWindow&); - const ResizableWindow& operator= (const ResizableWindow&); + @see MultiDocumentPanel +*/ +class JUCE_API MultiDocumentPanelWindow : public DocumentWindow +{ +public: - // (xxx remove these eventually) - // temporarily here to stop old code compiling, as the parameters for these methods have changed.. - void getBorderThickness (int& left, int& top, int& right, int& bottom); - // temporarily here to stop old code compiling, as the parameters for these methods have changed.. - void getContentComponentBorder (int& left, int& top, int& right, int& bottom); -}; + /** + */ + MultiDocumentPanelWindow (const Colour& backgroundColour); -#endif // __JUCE_RESIZABLEWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_ResizableWindow.h *********/ + /** Destructor. */ + ~MultiDocumentPanelWindow(); -/** - A resizable window with a title bar and maximise, minimise and close buttons. + /** @internal */ + void maximiseButtonPressed(); + /** @internal */ + void closeButtonPressed(); + /** @internal */ + void activeWindowStatusChanged(); + /** @internal */ + void broughtToFront(); - This subclass of ResizableWindow creates a fairly standard type of window with - a title bar and various buttons. The name of the component is shown in the - title bar, and an icon can optionally be specified with setIcon(). + juce_UseDebuggingNewOperator - All the methods available to a ResizableWindow are also available to this, - so it can easily be made resizable, minimised, maximised, etc. +private: + void updateOrder(); + MultiDocumentPanel* getOwner() const throw(); +}; - It's not advisable to add child components directly to a DocumentWindow: put them - inside your content component instead. And overriding methods like resized(), moved(), etc - is also not recommended - instead override these methods for your content component. - (If for some obscure reason you do need to override these methods, always remember to - call the super-class's resized() method too, otherwise it'll fail to lay out the window - decorations correctly). +/** + A component that contains a set of other components either in floating windows + or tabs. - You can also automatically add a menu bar to the window, using the setMenuBar() - method. + This acts as a panel that can be used to hold a set of open document windows, with + different layout modes. - @see ResizableWindow, DialogWindow + Use addDocument() and closeDocument() to add or remove components from the + panel - never use any of the Component methods to access the panel's child + components directly, as these are managed internally. */ -class JUCE_API DocumentWindow : public ResizableWindow +class JUCE_API MultiDocumentPanel : public Component, + private ComponentListener { public: - /** The set of available button-types that can be put on the title bar. - - @see setTitleBarButtonsRequired - */ - enum TitleBarButtons - { - minimiseButton = 1, - maximiseButton = 2, - closeButton = 4, - - /** A combination of all the buttons above. */ - allButtons = 7 - }; - - /** Creates a DocumentWindow. + /** Creates an empty panel. - @param name the name to give the component - this is also - the title shown at the top of the window. To change - this later, use setName() - @param backgroundColour the colour to use for filling the window's background. - @param requiredButtons specifies which of the buttons (close, minimise, maximise) - should be shown on the title bar. This value is a bitwise - combination of values from the TitleBarButtons enum. Note - that it can be "allButtons" to get them all. You - can change this later with the setTitleBarButtonsRequired() - method, which can also specify where they are positioned. - @param addToDesktop if true, the window will be automatically added to the - desktop; if false, you can use it as a child component - @see TitleBarButtons + Use addDocument() and closeDocument() to add or remove components from the + panel - never use any of the Component methods to access the panel's child + components directly, as these are managed internally. */ - DocumentWindow (const String& name, - const Colour& backgroundColour, - const int requiredButtons, - const bool addToDesktop = true); + MultiDocumentPanel(); /** Destructor. - If a content component has been set with setContentComponent(), it - will be deleted. + When deleted, this will call closeAllDocuments (false) to make sure all its + components are deleted. If you need to make sure all documents are saved + before closing, then you should call closeAllDocuments (true) and check that + it returns true before deleting the panel. */ - ~DocumentWindow(); + ~MultiDocumentPanel(); - /** Changes the component's name. + /** Tries to close all the documents. - (This is overridden from Component::setName() to cause a repaint, as - the name is what gets drawn across the window's title bar). - */ - void setName (const String& newName); + If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will + be called for each open document, and any of these calls fails, this method + will stop and return false, leaving some documents still open. - /** Sets an icon to show in the title bar, next to the title. + If checkItsOkToCloseFirst is false, then all documents will be closed + unconditionally. - A copy is made internally of the image, so the caller can delete the - image after calling this. If 0 is passed-in, any existing icon will be - removed. + @see closeDocument */ - void setIcon (const Image* imageToUse); + bool closeAllDocuments (const bool checkItsOkToCloseFirst); - /** Changes the height of the title-bar. */ - void setTitleBarHeight (const int newHeight); + /** Adds a document component to the panel. - /** Returns the current title bar height. */ - int getTitleBarHeight() const; + If the number of documents would exceed the limit set by setMaximumNumDocuments() then + this will fail and return false. (If it does fail, the component passed-in will not be + deleted, even if deleteWhenRemoved was set to true). - /** Changes the set of title-bar buttons being shown. + The MultiDocumentPanel will deal with creating a window border to go around your component, + so just pass in the bare content component here, no need to give it a ResizableWindow + or DocumentWindow. - @param requiredButtons specifies which of the buttons (close, minimise, maximise) - should be shown on the title bar. This value is a bitwise - combination of values from the TitleBarButtons enum. Note - that it can be "allButtons" to get them all. - @param positionTitleBarButtonsOnLeft if true, the buttons should go at the - left side of the bar; if false, they'll be placed at the right + @param component the component to add + @param backgroundColour the background colour to use to fill the component's + window or tab + @param deleteWhenRemoved if true, then when the component is removed by closeDocument() + or closeAllDocuments(), then it will be deleted. If false, then + the caller must handle the component's deletion */ - void setTitleBarButtonsRequired (const int requiredButtons, - const bool positionTitleBarButtonsOnLeft); + bool addDocument (Component* const component, + const Colour& backgroundColour, + const bool deleteWhenRemoved); - /** Sets whether the title should be centred within the window. + /** Closes one of the documents. - If true, the title text is shown in the middle of the title-bar; if false, - it'll be shown at the left of the bar. - */ - void setTitleBarTextCentred (const bool textShouldBeCentred); + If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will + be called, and if it fails, this method will return false without closing the + document. - /** Creates a menu inside this window. + If checkItsOkToCloseFirst is false, then the documents will be closed + unconditionally. - @param menuBarModel this specifies a MenuBarModel that should be used to - generate the contents of a menu bar that will be placed - just below the title bar, and just above any content - component. If this value is zero, any existing menu bar - will be removed from the component; if non-zero, one will - be added if it's required. - @param menuBarHeight the height of the menu bar component, if one is needed. Pass a value of zero - or less to use the look-and-feel's default size. + The component will be deleted if the deleteWhenRemoved parameter was set to + true when it was added with addDocument. + + @see addDocument, closeAllDocuments */ - void setMenuBar (MenuBarModel* menuBarModel, - const int menuBarHeight = 0); + bool closeDocument (Component* component, + const bool checkItsOkToCloseFirst); - /** This method is called when the user tries to close the window. + /** Returns the number of open document windows. - This is triggered by the user clicking the close button, or using some other - OS-specific key shortcut or OS menu for getting rid of a window. + @see getDocument + */ + int getNumDocuments() const throw(); - If the window is just a pop-up, you should override this closeButtonPressed() - method and make it delete the window in whatever way is appropriate for your - app. E.g. you might just want to call "delete this". + /** Returns one of the open documents. - If your app is centred around this window such that the whole app should quit when - the window is closed, then you will probably want to use this method as an opportunity - to call JUCEApplication::quit(), and leave the window to be deleted later by your - JUCEApplication::shutdown() method. (Doing it this way means that your window will - still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac - or closing it via the taskbar icon on Windows). + The order of the documents in this array may change when they are added, removed + or moved around. - (Note that the DocumentWindow class overrides Component::userTriedToCloseWindow() and - redirects it to call this method, so any methods of closing the window that are - caught by userTriedToCloseWindow() will also end up here). + @see getNumDocuments */ - virtual void closeButtonPressed(); + Component* getDocument (const int index) const throw(); - /** Callback that is triggered when the minimise button is pressed. + /** Returns the document component that is currently focused or on top. - The default implementation of this calls ResizableWindow::setMinimised(), but - you can override it to do more customised behaviour. + If currently using floating windows, then this will be the component in the currently + active window, or the top component if none are active. + + If it's currently in tabbed mode, then it'll return the component in the active tab. + + @see setActiveDocument */ - virtual void minimiseButtonPressed(); + Component* getActiveDocument() const throw(); - /** Callback that is triggered when the maximise button is pressed, or when the - title-bar is double-clicked. + /** Makes one of the components active and brings it to the top. - The default implementation of this calls ResizableWindow::setFullScreen(), but - you can override it to do more customised behaviour. + @see getActiveDocument */ - virtual void maximiseButtonPressed(); + void setActiveDocument (Component* component); - /** Returns the close button, (or 0 if there isn't one). */ - Button* getCloseButton() const throw(); + /** Callback which gets invoked when the currently-active document changes. */ + virtual void activeDocumentChanged(); - /** Returns the minimise button, (or 0 if there isn't one). */ - Button* getMinimiseButton() const throw(); + /** Sets a limit on how many windows can be open at once. - /** Returns the maximise button, (or 0 if there isn't one). */ - Button* getMaximiseButton() const throw(); + If this is zero or less there's no limit (the default). addDocument() will fail + if this number is exceeded. + */ + void setMaximumNumDocuments (const int maximumNumDocuments); - /** A set of colour IDs to use to change the colour of various aspects of the window. + /** Sets an option to make the document fullscreen if there's only one document open. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + If set to true, then if there's only one document, it'll fill the whole of this + component without tabs or a window border. If false, then tabs or a window + will always be shown, even if there's only one document. If there's more than + one document open, then this option makes no difference. + */ + void useFullscreenWhenOneDocument (const bool shouldUseTabs); - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + /** Returns the result of the last time useFullscreenWhenOneDocument() was called. */ - enum ColourIds + bool isFullscreenWhenOneDocument() const throw(); + + /** The different layout modes available. */ + enum LayoutMode { - textColourId = 0x1005701, /**< The colour to draw any text with. It's up to the look - and feel class how this is used. */ + FloatingWindows, /**< In this mode, there are overlapping DocumentWindow components for each document. */ + MaximisedWindowsWithTabs /**< In this mode, a TabbedComponent is used to show one document at a time. */ }; - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - const BorderSize getBorderThickness(); - /** @internal */ - const BorderSize getContentComponentBorder(); - /** @internal */ - void mouseDoubleClick (const MouseEvent& e); - /** @internal */ - void userTriedToCloseWindow(); - /** @internal */ - void activeWindowStatusChanged(); - /** @internal */ - int getDesktopWindowStyleFlags() const; - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - const Rectangle getTitleBarArea(); + /** Changes the panel's mode. - juce_UseDebuggingNewOperator + @see LayoutMode, getLayoutMode + */ + void setLayoutMode (const LayoutMode newLayoutMode); + + /** Returns the current layout mode. */ + LayoutMode getLayoutMode() const throw() { return mode; } + + /** Sets the background colour for the whole panel. + + Each document has its own background colour, but this is the one used to fill the areas + behind them. + */ + void setBackgroundColour (const Colour& newBackgroundColour); + + /** Returns the current background colour. + + @see setBackgroundColour + */ + const Colour& getBackgroundColour() const throw() { return backgroundColour; } + + /** A subclass must override this to say whether its currently ok for a document + to be closed. + + This method is called by closeDocument() and closeAllDocuments() to indicate that + a document should be saved if possible, ready for it to be closed. + + If this method returns true, then it means the document is ok and can be closed. + + If it returns false, then it means that the closeDocument() method should stop + and not close. + + Normally, you'd use this method to ask the user if they want to save any changes, + then return true if the save operation went ok. If the user cancelled the save + operation you could return false here to abort the close operation. + + If your component is based on the FileBasedDocument class, then you'd probably want + to call FileBasedDocument::saveIfNeededAndUserAgrees() and return true if this returned + FileBasedDocument::savedOk + + @see closeDocument, FileBasedDocument::saveIfNeededAndUserAgrees() + */ + virtual bool tryToCloseDocument (Component* component) = 0; + + /** Creates a new window to be used for a document. + + The default implementation of this just returns a basic MultiDocumentPanelWindow object, + but you might want to override it to return a custom component. + */ + virtual MultiDocumentPanelWindow* createNewDocumentWindow(); + + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void componentNameChanged (Component&); + + juce_UseDebuggingNewOperator private: - int titleBarHeight, menuBarHeight, requiredButtons; - bool positionTitleBarButtonsOnLeft, drawTitleTextCentred; - Button* titleBarButtons [3]; - Image* titleBarIcon; - MenuBarComponent* menuBar; - MenuBarModel* menuBarModel; + LayoutMode mode; + Array components; + TabbedComponent* tabComponent; + Colour backgroundColour; + int maximumNumDocuments, numDocsBeforeTabsUsed; + + friend class MultiDocumentPanelWindow; + friend class MDITabbedComponentInternal; + + Component* getContainerComp (Component* c) const; + void updateOrder(); + + void addWindow (Component* component); +}; + +#endif // __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__ +/********* End of inlined file: juce_MultiDocumentPanel.h *********/ + +#endif +#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ + +#endif +#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ + +#endif +#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ + +#endif +#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ + +/********* Start of inlined file: juce_StretchableLayoutManager.h *********/ +#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ +#define __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ + +/** + For laying out a set of components, where the components have preferred sizes + and size limits, but where they are allowed to stretch to fill the available + space. + + For example, if you have a component containing several other components, and + each one should be given a share of the total size, you could use one of these + to resize the child components when the parent component is resized. Then + you could add a StretchableLayoutResizerBar to easily let the user rescale them. + + A StretchableLayoutManager operates only in one dimension, so if you have a set + of components stacked vertically on top of each other, you'd use one to manage their + heights. To build up complex arrangements of components, e.g. for applications + with multiple nested panels, you would use more than one StretchableLayoutManager. + E.g. by using two (one vertical, one horizontal), you could create a resizable + spreadsheet-style table. + + E.g. + @code + class MyComp : public Component + { + StretchableLayoutManager myLayout; + + MyComp() + { + myLayout.setItemLayout (0, // for item 0 + 50, 100, // must be between 50 and 100 pixels in size + -0.6); // and its preferred size is 60% of the total available space + + myLayout.setItemLayout (1, // for item 1 + -0.2, -0.6, // size must be between 20% and 60% of the available space + 50); // and its preferred size is 50 pixels + } + + void resized() + { + // make a list of two of our child components that we want to reposition + Component* comps[] = { myComp1, myComp2 }; + + // this will position the 2 components, one above the other, to fit + // vertically into the rectangle provided. + myLayout.layOutComponents (comps, 2, + 0, 0, getWidth(), getHeight(), + true); + } + }; + @endcode + + @see StretchableLayoutResizerBar +*/ +class JUCE_API StretchableLayoutManager +{ +public: + + /** Creates an empty layout. + + You'll need to add some item properties to the layout before it can be used + to resize things - see setItemLayout(). + */ + StretchableLayoutManager(); + + /** Destructor. */ + ~StretchableLayoutManager(); + + /** For a numbered item, this sets its size limits and preferred size. + + @param itemIndex the index of the item to change. + @param minimumSize the minimum size that this item is allowed to be - a positive number + indicates an absolute size in pixels. A negative number indicates a + proportion of the available space (e.g -0.5 is 50%) + @param maximumSize the maximum size that this item is allowed to be - a positive number + indicates an absolute size in pixels. A negative number indicates a + proportion of the available space + @param preferredSize the size that this item would like to be, if there's enough room. A + positive number indicates an absolute size in pixels. A negative number + indicates a proportion of the available space + @see getItemLayout + */ + void setItemLayout (const int itemIndex, + const double minimumSize, + const double maximumSize, + const double preferredSize); + + /** For a numbered item, this returns its size limits and preferred size. + + @param itemIndex the index of the item. + @param minimumSize the minimum size that this item is allowed to be - a positive number + indicates an absolute size in pixels. A negative number indicates a + proportion of the available space (e.g -0.5 is 50%) + @param maximumSize the maximum size that this item is allowed to be - a positive number + indicates an absolute size in pixels. A negative number indicates a + proportion of the available space + @param preferredSize the size that this item would like to be, if there's enough room. A + positive number indicates an absolute size in pixels. A negative number + indicates a proportion of the available space + @returns false if the item's properties hadn't been set + @see setItemLayout + */ + bool getItemLayout (const int itemIndex, + double& minimumSize, + double& maximumSize, + double& preferredSize) const; + + /** Clears all the properties that have been set with setItemLayout() and resets + this object to its initial state. + */ + void clearAllItems(); + + /** Takes a set of components that correspond to the layout's items, and positions + them to fill a space. + + This will try to give each item its preferred size, whether that's a relative size + or an absolute one. + + @param components an array of components that correspond to each of the + numbered items that the StretchableLayoutManager object + has been told about with setItemLayout() + @param numComponents the number of components in the array that is passed-in. This + should be the same as the number of items this object has been + told about. + @param x the left of the rectangle in which the components should + be laid out + @param y the top of the rectangle in which the components should + be laid out + @param width the width of the rectangle in which the components should + be laid out + @param height the height of the rectangle in which the components should + be laid out + @param vertically if true, the components will be positioned in a vertical stack, + so that they fill the height of the rectangle. If false, they + will be placed side-by-side in a horizontal line, filling the + available width + @param resizeOtherDimension if true, this means that the components will have their + other dimension resized to fit the space - i.e. if the 'vertically' + parameter is true, their x-positions and widths are adjusted to fit + the x and width parameters; if 'vertically' is false, their y-positions + and heights are adjusted to fit the y and height parameters. + */ + void layOutComponents (Component** const components, + int numComponents, + int x, int y, int width, int height, + const bool vertically, + const bool resizeOtherDimension); + + /** Returns the current position of one of the items. + + This is only a valid call after layOutComponents() has been called, as it + returns the last position that this item was placed at. If the layout was + vertical, the value returned will be the y position of the top of the item, + relative to the top of the rectangle in which the items were placed (so for + example, item 0 will always have position of 0, even in the rectangle passed + in to layOutComponents() wasn't at y = 0). If the layout was done horizontally, + the position returned is the item's left-hand position, again relative to the + x position of the rectangle used. + + @see getItemCurrentSize, setItemPosition + */ + int getItemCurrentPosition (const int itemIndex) const; + + /** Returns the current size of one of the items. + + This is only meaningful after layOutComponents() has been called, as it + returns the last size that this item was given. If the layout was done + vertically, it'll return the item's height in pixels; if it was horizontal, + it'll return its width. + + @see getItemCurrentRelativeSize + */ + int getItemCurrentAbsoluteSize (const int itemIndex) const; + + /** Returns the current size of one of the items. + + This is only meaningful after layOutComponents() has been called, as it + returns the last size that this item was given. If the layout was done + vertically, it'll return a negative value representing the item's height relative + to the last size used for laying the components out; if the layout was done + horizontally it'll be the proportion of its width. + + @see getItemCurrentAbsoluteSize + */ + double getItemCurrentRelativeSize (const int itemIndex) const; + + /** Moves one of the items, shifting along any other items as necessary in + order to get it to the desired position. + + Calling this method will also update the preferred sizes of the items it + shuffles along, so that they reflect their new positions. + + (This is the method that a StretchableLayoutResizerBar uses to shift the items + about when it's dragged). + + @param itemIndex the item to move + @param newPosition the absolute position that you'd like this item to move + to. The item might not be able to always reach exactly this position, + because other items may have minimum sizes that constrain how + far it can go + */ + void setItemPosition (const int itemIndex, + int newPosition); + + juce_UseDebuggingNewOperator + +private: + struct ItemLayoutProperties + { + int itemIndex; + int currentSize; + double minSize, maxSize, preferredSize; + }; + + OwnedArray items; + int totalSize; + + static int sizeToRealSize (double size, int totalSpace); + + ItemLayoutProperties* getInfoFor (const int itemIndex) const; + + void setTotalSize (const int newTotalSize); + + int fitComponentsIntoSpace (const int startIndex, + const int endIndex, + const int availableSpace, + int startPos); + + int getMinimumSizeOfItems (const int startIndex, const int endIndex) const; + int getMaximumSizeOfItems (const int startIndex, const int endIndex) const; + + void updatePrefSizesToMatchCurrentPositions(); + + StretchableLayoutManager (const StretchableLayoutManager&); + const StretchableLayoutManager& operator= (const StretchableLayoutManager&); +}; + +#endif // __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ +/********* End of inlined file: juce_StretchableLayoutManager.h *********/ + +#endif +#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ + +/********* Start of inlined file: juce_StretchableLayoutResizerBar.h *********/ +#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ +#define __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ + +/** + A component that acts as one of the vertical or horizontal bars you see being + used to resize panels in a window. + + One of these acts with a StretchableLayoutManager to resize the other components. + + @see StretchableLayoutManager +*/ +class JUCE_API StretchableLayoutResizerBar : public Component +{ +public: + + /** Creates a resizer bar for use on a specified layout. + + @param layoutToUse the layout that will be affected when this bar + is dragged + @param itemIndexInLayout the item index in the layout that corresponds to + this bar component. You'll need to set up the item + properties in a suitable way for a divider bar, e.g. + for an 8-pixel wide bar which, you could call + myLayout->setItemLayout (barIndex, 8, 8, 8) + @param isBarVertical true if it's an upright bar that you drag left and + right; false for a horizontal one that you drag up and + down + */ + StretchableLayoutResizerBar (StretchableLayoutManager* const layoutToUse, + const int itemIndexInLayout, + const bool isBarVertical); + + /** Destructor. */ + ~StretchableLayoutResizerBar(); + + /** This is called when the bar is dragged. + + This method must update the positions of any components whose position is + determined by the StretchableLayoutManager, because they might have just + moved. + + The default implementation calls the resized() method of this component's + parent component, because that's often where you're likely to apply the + layout, but it can be overridden for more specific needs. + */ + virtual void hasBeenMoved(); + + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + + juce_UseDebuggingNewOperator + +private: + StretchableLayoutManager* layout; + int itemIndex, mouseDownPos; + bool isVertical; + + StretchableLayoutResizerBar (const StretchableLayoutResizerBar&); + const StretchableLayoutResizerBar& operator= (const StretchableLayoutResizerBar&); +}; + +#endif // __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ +/********* End of inlined file: juce_StretchableLayoutResizerBar.h *********/ + +#endif +#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ + +/********* Start of inlined file: juce_StretchableObjectResizer.h *********/ +#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ +#define __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ + +/** + A utility class for fitting a set of objects whose sizes can vary between + a minimum and maximum size, into a space. + + This is a trickier algorithm than it would first seem, so I've put it in this + class to allow it to be shared by various bits of code. + + To use it, create one of these objects, call addItem() to add the list of items + you need, then call resizeToFit(), which will change all their sizes. You can + then retrieve the new sizes with getItemSize() and getNumItems(). + + It's currently used by the TableHeaderComponent for stretching out the table + headings to fill the table's width. +*/ +class StretchableObjectResizer +{ +public: + + /** Creates an empty object resizer. */ + StretchableObjectResizer(); + + /** Destructor. */ + ~StretchableObjectResizer(); + + /** Adds an item to the list. + + The order parameter lets you specify groups of items that are resized first when some + space needs to be found. Those items with an order of 0 will be the first ones to be + resized, and if that doesn't provide enough space to meet the requirements, the algorithm + will then try resizing the items with an order of 1, then 2, and so on. + */ + void addItem (const double currentSize, + const double minSize, + const double maxSize, + const int order = 0); + + /** Resizes all the items to fit this amount of space. + + This will attempt to fit them in without exceeding each item's miniumum and + maximum sizes. In cases where none of the items can be expanded or enlarged any + further, the final size may be greater or less than the size passed in. + + After calling this method, you can retrieve the new sizes with the getItemSize() + method. + */ + void resizeToFit (const double targetSize); + + /** Returns the number of items that have been added. */ + int getNumItems() const throw() { return items.size(); } + + /** Returns the size of one of the items. */ + double getItemSize (const int index) const throw(); + + juce_UseDebuggingNewOperator + +private: + struct Item + { + double size; + double minSize; + double maxSize; + int order; + }; + + OwnedArray items; + + StretchableObjectResizer (const StretchableObjectResizer&); + const StretchableObjectResizer& operator= (const StretchableObjectResizer&); +}; + +#endif // __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ +/********* End of inlined file: juce_StretchableObjectResizer.h *********/ + +#endif +#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__ + +#endif +#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__ + +#endif +#ifndef __JUCE_VIEWPORT_JUCEHEADER__ + +#endif +#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ + +/********* Start of inlined file: juce_LookAndFeel.h *********/ +#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ +#define __JUCE_LOOKANDFEEL_JUCEHEADER__ + +/********* Start of inlined file: juce_AlertWindow.h *********/ +#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ +#define __JUCE_ALERTWINDOW_JUCEHEADER__ + +/********* Start of inlined file: juce_TextLayout.h *********/ +#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ +#define __JUCE_TEXTLAYOUT_JUCEHEADER__ + +class Graphics; + +/** + A laid-out arrangement of text. + + You can add text in different fonts to a TextLayout object, then call its + layout() method to word-wrap it into lines. The layout can then be drawn + using a graphics context. + + It's handy if you've got a message to display, because you can format it, + measure the extent of the layout, and then create a suitably-sized window + to show it in. + + @see Font, Graphics::drawFittedText, GlyphArrangement +*/ +class JUCE_API TextLayout +{ +public: + + /** Creates an empty text layout. + + Text can then be appended using the appendText() method. + */ + TextLayout() throw(); + + /** Creates a copy of another layout object. */ + TextLayout (const TextLayout& other) throw(); + + /** Creates a text layout from an initial string and font. */ + TextLayout (const String& text, const Font& font) throw(); + + /** Destructor. */ + ~TextLayout() throw(); + + /** Copies another layout onto this one. */ + const TextLayout& operator= (const TextLayout& layoutToCopy) throw(); + + /** Clears the layout, removing all its text. */ + void clear() throw(); + + /** Adds a string to the end of the arrangement. + + The string will be broken onto new lines wherever it contains + carriage-returns or linefeeds. After adding it, you can call layout() + to wrap long lines into a paragraph and justify it. + */ + void appendText (const String& textToAppend, + const Font& fontToUse) throw(); + + /** Replaces all the text with a new string. + + This is equivalent to calling clear() followed by appendText(). + */ + void setText (const String& newText, + const Font& fontToUse) throw(); + + /** Breaks the text up to form a paragraph with the given width. + + @param maximumWidth any text wider than this will be split + across multiple lines + @param justification how the lines are to be laid-out horizontally + @param attemptToBalanceLineLengths if true, it will try to split the lines at a + width that keeps all the lines of text at a + similar length - this is good when you're displaying + a short message and don't want it to get split + onto two lines with only a couple of words on + the second line, which looks untidy. + */ + void layout (int maximumWidth, + const Justification& justification, + const bool attemptToBalanceLineLengths) throw(); + + /** Returns the overall width of the entire text layout. */ + int getWidth() const throw(); + + /** Returns the overall height of the entire text layout. */ + int getHeight() const throw(); + + /** Returns the total number of lines of text. */ + int getNumLines() const throw() { return totalLines; } + + /** Returns the width of a particular line of text. + + @param lineNumber the line, from 0 to (getNumLines() - 1) + */ + int getLineWidth (const int lineNumber) const throw(); + + /** Renders the text at a specified position using a graphics context. + */ + void draw (Graphics& g, + const int topLeftX, + const int topLeftY) const throw(); + + /** Renders the text within a specified rectangle using a graphics context. + + The justification flags dictate how the block of text should be positioned + within the rectangle. + */ + void drawWithin (Graphics& g, + int x, int y, int w, int h, + const Justification& layoutFlags) const throw(); + + juce_UseDebuggingNewOperator + +private: + VoidArray tokens; + int totalLines; +}; + +#endif // __JUCE_TEXTLAYOUT_JUCEHEADER__ +/********* End of inlined file: juce_TextLayout.h *********/ + +/** A window that displays a message and has buttons for the user to react to it. + + For simple dialog boxes with just a couple of buttons on them, there are + some static methods for running these. + + For more complex dialogs, an AlertWindow can be created, then it can have some + buttons and components added to it, and its runModalLoop() method is then used to + show it. The value returned by runModalLoop() shows which button the + user pressed to dismiss the box. + + @see ThreadWithProgressWindow +*/ +class JUCE_API AlertWindow : public TopLevelWindow, + private ButtonListener +{ +public: + + /** The type of icon to show in the dialog box. */ + enum AlertIconType + { + NoIcon, /**< No icon will be shown on the dialog box. */ + QuestionIcon, /**< A question-mark icon, for dialog boxes that need the + user to answer a question. */ + WarningIcon, /**< An exclamation mark to indicate that the dialog is a + warning about something and shouldn't be ignored. */ + InfoIcon /**< An icon that indicates that the dialog box is just + giving the user some information, which doesn't require + a response from them. */ + }; + + /** Creates an AlertWindow. + + @param title the headline to show at the top of the dialog box + @param message a longer, more descriptive message to show underneath the + headline + @param iconType the type of icon to display + @param associatedComponent if this is non-zero, it specifies the component that the + alert window should be associated with. Depending on the look + and feel, this might be used for positioning of the alert window. + */ + AlertWindow (const String& title, + const String& message, + AlertIconType iconType, + Component* associatedComponent = 0); + + /** Destroys the AlertWindow */ + ~AlertWindow(); + + /** Returns the type of alert icon that was specified when the window + was created. */ + AlertIconType getAlertType() const throw() { return alertIconType; } + + /** Changes the dialog box's message. + + This will also resize the window to fit the new message if required. + */ + void setMessage (const String& message); + + /** Adds a button to the window. + + @param name the text to show on the button + @param returnValue the value that should be returned from runModalLoop() + if this is the button that the user presses. + @param shortcutKey1 an optional key that can be pressed to trigger this button + @param shortcutKey2 a second optional key that can be pressed to trigger this button + */ + void addButton (const String& name, + const int returnValue, + const KeyPress& shortcutKey1 = KeyPress(), + const KeyPress& shortcutKey2 = KeyPress()); + + /** Returns the number of buttons that the window currently has. */ + int getNumButtons() const; + + /** Adds a textbox to the window for entering strings. + + @param name an internal name for the text-box. This is the name to pass to + the getTextEditorContents() method to find out what the + user typed-in. + @param initialContents a string to show in the text box when it's first shown + @param onScreenLabel if this is non-empty, it will be displayed next to the + text-box to label it. + @param isPasswordBox if true, the text editor will display asterisks instead of + the actual text + @see getTextEditorContents + */ + void addTextEditor (const String& name, + const String& initialContents, + const String& onScreenLabel = String::empty, + const bool isPasswordBox = false); + + /** Returns the contents of a named textbox. + + After showing an AlertWindow that contains a text editor, this can be + used to find out what the user has typed into it. + + @param nameOfTextEditor the name of the text box that you're interested in + @see addTextEditor + */ + const String getTextEditorContents (const String& nameOfTextEditor) const; + + /** Adds a drop-down list of choices to the box. + + After the box has been shown, the getComboBoxComponent() method can + be used to find out which item the user picked. + + @param name the label to use for the drop-down list + @param items the list of items to show in it + @param onScreenLabel if this is non-empty, it will be displayed next to the + combo-box to label it. + @see getComboBoxComponent + */ + void addComboBox (const String& name, + const StringArray& items, + const String& onScreenLabel = String::empty); + + /** Returns a drop-down list that was added to the AlertWindow. + + @param nameOfList the name that was passed into the addComboBox() method + when creating the drop-down + @returns the ComboBox component, or 0 if none was found for the given name. + */ + ComboBox* getComboBoxComponent (const String& nameOfList) const; + + /** Adds a block of text. + + This is handy for adding a multi-line note next to a textbox or combo-box, + to provide more details about what's going on. + */ + void addTextBlock (const String& text); + + /** Adds a progress-bar to the window. + + @param progressValue a variable that will be repeatedly checked while the + dialog box is visible, to see how far the process has + got. The value should be in the range 0 to 1.0 + */ + void addProgressBarComponent (double& progressValue); + + /** Adds a user-defined component to the dialog box. + + @param component the component to add - its size should be set up correctly + before it is passed in. The caller is responsible for deleting + the component later on - the AlertWindow won't delete it. + */ + void addCustomComponent (Component* const component); + + /** Returns the number of custom components in the dialog box. + + @see getCustomComponent, addCustomComponent + */ + int getNumCustomComponents() const; + + /** Returns one of the custom components in the dialog box. + + @param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes + will return 0 + @see getNumCustomComponents, addCustomComponent + */ + Component* getCustomComponent (const int index) const; + + /** Removes one of the custom components in the dialog box. + + Note that this won't delete it, it just removes the component from the window + + @param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes + will return 0 + @returns the component that was removed (or zero) + @see getNumCustomComponents, addCustomComponent + */ + Component* removeCustomComponent (const int index); + + /** Returns true if the window contains any components other than just buttons.*/ + bool containsAnyExtraComponents() const; + + // easy-to-use message box functions: + + /** Shows a dialog box that just has a message and a single button to get rid of it. + + The box is shown modally, and the method returns after the user + has clicked the button (or pressed the escape or return keys). + + @param iconType the type of icon to show + @param title the headline to show at the top of the box + @param message a longer, more descriptive message to show underneath the + headline + @param buttonText the text to show in the button - if this string is empty, the + default string "ok" (or a localised version) will be used. + @param associatedComponent if this is non-zero, it specifies the component that the + alert window should be associated with. Depending on the look + and feel, this might be used for positioning of the alert window. + */ + static void JUCE_CALLTYPE showMessageBox (AlertIconType iconType, + const String& title, + const String& message, + const String& buttonText = String::empty, + Component* associatedComponent = 0); + + /** Shows a dialog box with two buttons. + + Ideal for ok/cancel or yes/no choices. The return key can also be used + to trigger the first button, and the escape key for the second button. + + @param iconType the type of icon to show + @param title the headline to show at the top of the box + @param message a longer, more descriptive message to show underneath the + headline + @param button1Text the text to show in the first button - if this string is + empty, the default string "ok" (or a localised version of it) + will be used. + @param button2Text the text to show in the second button - if this string is + empty, the default string "cancel" (or a localised version of it) + will be used. + @param associatedComponent if this is non-zero, it specifies the component that the + alert window should be associated with. Depending on the look + and feel, this might be used for positioning of the alert window. + @returns true if button 1 was clicked, false if it was button 2 + */ + static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType, + const String& title, + const String& message, + const String& button1Text = String::empty, + const String& button2Text = String::empty, + Component* associatedComponent = 0); + + /** Shows a dialog box with three buttons. + + Ideal for yes/no/cancel boxes. + + The escape key can be used to trigger the third button. + + @param iconType the type of icon to show + @param title the headline to show at the top of the box + @param message a longer, more descriptive message to show underneath the + headline + @param button1Text the text to show in the first button - if an empty string, then + "yes" will be used (or a localised version of it) + @param button2Text the text to show in the first button - if an empty string, then + "no" will be used (or a localised version of it) + @param button3Text the text to show in the first button - if an empty string, then + "cancel" will be used (or a localised version of it) + @param associatedComponent if this is non-zero, it specifies the component that the + alert window should be associated with. Depending on the look + and feel, this might be used for positioning of the alert window. + + @returns one of the following values: + - 0 if the third button was pressed (normally used for 'cancel') + - 1 if the first button was pressed (normally used for 'yes') + - 2 if the middle button was pressed (normally used for 'no') + */ + static int JUCE_CALLTYPE showYesNoCancelBox (AlertIconType iconType, + const String& title, + const String& message, + const String& button1Text = String::empty, + const String& button2Text = String::empty, + const String& button3Text = String::empty, + Component* associatedComponent = 0); + + /** Shows an operating-system native dialog box. + + @param title the title to use at the top + @param bodyText the longer message to show + @param isOkCancel if true, this will show an ok/cancel box, if false, + it'll show a box with just an ok button + @returns true if the ok button was pressed, false if they pressed cancel. + */ + static bool JUCE_CALLTYPE showNativeDialogBox (const String& title, + const String& bodyText, + bool isOkCancel); + + /** A set of colour IDs to use to change the colour of various aspects of the alert box. + + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. + + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + backgroundColourId = 0x1001800, /**< The background colour for the window. */ + textColourId = 0x1001810, /**< The colour for the text. */ + outlineColourId = 0x1001820 /**< An optional colour to use to draw a border around the window. */ + }; + + juce_UseDebuggingNewOperator + +protected: + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + bool keyPressed (const KeyPress& key); + /** @internal */ + void buttonClicked (Button* button); + /** @internal */ + void lookAndFeelChanged(); + /** @internal */ + void userTriedToCloseWindow(); + /** @internal */ + int getDesktopWindowStyleFlags() const; + +private: + String text; + TextLayout textLayout; + AlertIconType alertIconType; + ComponentBoundsConstrainer constrainer; + ComponentDragger dragger; + Rectangle textArea; + VoidArray buttons, textBoxes, comboBoxes; + VoidArray progressBars, customComps, textBlocks, allComps; + StringArray textboxNames, comboBoxNames; + Font font; + Component* associatedComponent; + + void updateLayout (const bool onlyIncreaseSize); + + // disable copy constructor + AlertWindow (const AlertWindow&); + const AlertWindow& operator= (const AlertWindow&); +}; + +#endif // __JUCE_ALERTWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_AlertWindow.h *********/ + +class ToggleButton; +class TextButton; +class AlertWindow; +class TextLayout; +class ScrollBar; +class BubbleComponent; +class ComboBox; +class Button; +class FilenameComponent; +class DocumentWindow; +class ResizableWindow; +class GroupComponent; +class MenuBarComponent; +class DropShadower; +class GlyphArrangement; +class PropertyComponent; +class TableHeaderComponent; +class Toolbar; +class ToolbarItemComponent; +class PopupMenu; +class ProgressBar; +class FileBrowserComponent; +class DirectoryContentsDisplayComponent; +class FilePreviewComponent; +class ImageButton; + +/** + LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses + can be used to apply different 'skins' to the application. + +*/ +class JUCE_API LookAndFeel +{ +public: + + /** Creates the default JUCE look and feel. */ + LookAndFeel(); + + /** Destructor. */ + virtual ~LookAndFeel(); + + /** Returns the current default look-and-feel for a component to use when it + hasn't got one explicitly set. + + @see setDefaultLookAndFeel + */ + static LookAndFeel& getDefaultLookAndFeel() throw(); + + /** Changes the default look-and-feel. + + @param newDefaultLookAndFeel the new look-and-feel object to use - if this is + set to 0, it will revert to using the default one. The + object passed-in must be deleted by the caller when + it's no longer needed. + @see getDefaultLookAndFeel + */ + static void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) throw(); + + /** Looks for a colour that has been registered with the given colour ID number. + + If a colour has been set for this ID number using setColour(), then it is + returned. If none has been set, it will just return Colours::black. + + The colour IDs for various purposes are stored as enums in the components that + they are relevent to - for an example, see Slider::ColourIds, + Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. + + If you're looking up a colour for use in drawing a component, it's usually + best not to call this directly, but to use the Component::findColour() method + instead. That will first check whether a suitable colour has been registered + directly with the component, and will fall-back on calling the component's + LookAndFeel's findColour() method if none is found. + + @see setColour, Component::findColour, Component::setColour + */ + const Colour findColour (const int colourId) const throw(); + + /** Registers a colour to be used for a particular purpose. + + For more details, see the comments for findColour(). + + @see findColour, Component::findColour, Component::setColour + */ + void setColour (const int colourId, const Colour& colour) throw(); + + /** Returns true if the specified colour ID has been explicitly set using the + setColour() method. + */ + bool isColourSpecified (const int colourId) const throw(); + + virtual const Typeface::Ptr getTypefaceForFont (const Font& font); + + /** Allows you to change the default sans-serif font. + + If you need to supply your own Typeface object for any of the default fonts, rather + than just supplying the name (e.g. if you want to use an embedded font), then + you should instead override getTypefaceForFont() to create and return the typeface. + */ + void setDefaultSansSerifTypefaceName (const String& newName); + + /** Override this to get the chance to swap a component's mouse cursor for a + customised one. + */ + virtual const MouseCursor getMouseCursorFor (Component& component); + + /** Draws the lozenge-shaped background for a standard button. */ + virtual void drawButtonBackground (Graphics& g, + Button& button, + const Colour& backgroundColour, + bool isMouseOverButton, + bool isButtonDown); + + virtual const Font getFontForTextButton (TextButton& button); + + /** Draws the text for a TextButton. */ + virtual void drawButtonText (Graphics& g, + TextButton& button, + bool isMouseOverButton, + bool isButtonDown); + + /** Draws the contents of a standard ToggleButton. */ + virtual void drawToggleButton (Graphics& g, + ToggleButton& button, + bool isMouseOverButton, + bool isButtonDown); + + virtual void changeToggleButtonWidthToFitText (ToggleButton& button); + + virtual void drawTickBox (Graphics& g, + Component& component, + int x, int y, int w, int h, + const bool ticked, + const bool isEnabled, + const bool isMouseOverButton, + const bool isButtonDown); + + /* AlertWindow handling.. + */ + virtual AlertWindow* createAlertWindow (const String& title, + const String& message, + const String& button1, + const String& button2, + const String& button3, + AlertWindow::AlertIconType iconType, + int numButtons, + Component* associatedComponent); + + virtual void drawAlertBox (Graphics& g, + AlertWindow& alert, + const Rectangle& textArea, + TextLayout& textLayout); + + virtual int getAlertBoxWindowFlags(); + + virtual int getAlertWindowButtonHeight(); + + virtual const Font getAlertWindowFont(); + + /** Draws a progress bar. + + If the progress value is less than 0 or greater than 1.0, this should draw a spinning + bar that fills the whole space (i.e. to say that the app is still busy but the progress + isn't known). It can use the current time as a basis for playing an animation. + + (Used by progress bars in AlertWindow). + */ + virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar, + int width, int height, + double progress, const String& textToShow); + + // Draws a small image that spins to indicate that something's happening.. + // This method should use the current time to animate itself, so just keep + // repainting it every so often. + virtual void drawSpinningWaitAnimation (Graphics& g, const Colour& colour, + int x, int y, int w, int h); + + /** Draws one of the buttons on a scrollbar. + + @param g the context to draw into + @param scrollbar the bar itself + @param width the width of the button + @param height the height of the button + @param buttonDirection the direction of the button, where 0 = up, 1 = right, 2 = down, 3 = left + @param isScrollbarVertical true if it's a vertical bar, false if horizontal + @param isMouseOverButton whether the mouse is currently over the button (also true if it's held down) + @param isButtonDown whether the mouse button's held down + */ + virtual void drawScrollbarButton (Graphics& g, + ScrollBar& scrollbar, + int width, int height, + int buttonDirection, + bool isScrollbarVertical, + bool isMouseOverButton, + bool isButtonDown); + + /** Draws the thumb area of a scrollbar. + + @param g the context to draw into + @param scrollbar the bar itself + @param x the x position of the left edge of the thumb area to draw in + @param y the y position of the top edge of the thumb area to draw in + @param width the width of the thumb area to draw in + @param height the height of the thumb area to draw in + @param isScrollbarVertical true if it's a vertical bar, false if horizontal + @param thumbStartPosition for vertical bars, the y co-ordinate of the top of the + thumb, or its x position for horizontal bars + @param thumbSize for vertical bars, the height of the thumb, or its width for + horizontal bars. This may be 0 if the thumb shouldn't be drawn. + @param isMouseOver whether the mouse is over the thumb area, also true if the mouse is + currently dragging the thumb + @param isMouseDown whether the mouse is currently dragging the scrollbar + */ + virtual void drawScrollbar (Graphics& g, + ScrollBar& scrollbar, + int x, int y, + int width, int height, + bool isScrollbarVertical, + int thumbStartPosition, + int thumbSize, + bool isMouseOver, + bool isMouseDown); + + /** Returns the component effect to use for a scrollbar */ + virtual ImageEffectFilter* getScrollbarEffect(); + + /** Returns the minimum length in pixels to use for a scrollbar thumb. */ + virtual int getMinimumScrollbarThumbSize (ScrollBar& scrollbar); + + /** Returns the default thickness to use for a scrollbar. */ + virtual int getDefaultScrollbarWidth(); + + /** Returns the length in pixels to use for a scrollbar button. */ + virtual int getScrollbarButtonSize (ScrollBar& scrollbar); + + /** Returns a tick shape for use in yes/no boxes, etc. */ + virtual const Path getTickShape (const float height); + /** Returns a cross shape for use in yes/no boxes, etc. */ + virtual const Path getCrossShape (const float height); + + /** Draws the + or - box in a treeview. */ + virtual void drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus, bool isMouseOver); + + virtual void fillTextEditorBackground (Graphics& g, int width, int height, TextEditor& textEditor); + virtual void drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor); + + // these return an image from the ImageCache, so use ImageCache::release() to free it + virtual Image* getDefaultFolderImage(); + virtual Image* getDefaultDocumentFileImage(); + + virtual void createFileChooserHeaderText (const String& title, + const String& instructions, + GlyphArrangement& destArrangement, + int width); + + virtual void drawFileBrowserRow (Graphics& g, int width, int height, + const String& filename, Image* icon, + const String& fileSizeDescription, + const String& fileTimeDescription, + const bool isDirectory, + const bool isItemSelected, + const int itemIndex); + + virtual Button* createFileBrowserGoUpButton(); + + virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp, + DirectoryContentsDisplayComponent* fileListComponent, + FilePreviewComponent* previewComp, + ComboBox* currentPathBox, + TextEditor* filenameBox, + Button* goUpButton); + + virtual void drawBubble (Graphics& g, + float tipX, float tipY, + float boxX, float boxY, float boxW, float boxH); + + /** Fills the background of a popup menu component. */ + virtual void drawPopupMenuBackground (Graphics& g, int width, int height); + + /** Draws one of the items in a popup menu. */ + virtual void drawPopupMenuItem (Graphics& g, + int width, int height, + const bool isSeparator, + const bool isActive, + const bool isHighlighted, + const bool isTicked, + const bool hasSubMenu, + const String& text, + const String& shortcutKeyText, + Image* image, + const Colour* const textColour); + + /** Returns the size and style of font to use in popup menus. */ + virtual const Font getPopupMenuFont(); + + virtual void drawPopupMenuUpDownArrow (Graphics& g, + int width, int height, + bool isScrollUpArrow); + + /** Finds the best size for an item in a popup menu. */ + virtual void getIdealPopupMenuItemSize (const String& text, + const bool isSeparator, + int standardMenuItemHeight, + int& idealWidth, + int& idealHeight); + + virtual int getMenuWindowFlags(); + + virtual void drawMenuBarBackground (Graphics& g, int width, int height, + bool isMouseOverBar, + MenuBarComponent& menuBar); + + virtual int getMenuBarItemWidth (MenuBarComponent& menuBar, int itemIndex, const String& itemText); + + virtual const Font getMenuBarFont (MenuBarComponent& menuBar, int itemIndex, const String& itemText); + + virtual void drawMenuBarItem (Graphics& g, + int width, int height, + int itemIndex, + const String& itemText, + bool isMouseOverItem, + bool isMenuOpen, + bool isMouseOverBar, + MenuBarComponent& menuBar); + + virtual void drawComboBox (Graphics& g, int width, int height, + const bool isButtonDown, + int buttonX, int buttonY, + int buttonW, int buttonH, + ComboBox& box); + + virtual const Font getComboBoxFont (ComboBox& box); + + virtual Label* createComboBoxTextBox (ComboBox& box); + + virtual void positionComboBoxText (ComboBox& box, Label& labelToPosition); + + virtual void drawLabel (Graphics& g, Label& label); + + virtual void drawLinearSlider (Graphics& g, + int x, int y, + int width, int height, + float sliderPos, + float minSliderPos, + float maxSliderPos, + const Slider::SliderStyle style, + Slider& slider); + + virtual void drawLinearSliderBackground (Graphics& g, + int x, int y, + int width, int height, + float sliderPos, + float minSliderPos, + float maxSliderPos, + const Slider::SliderStyle style, + Slider& slider); + + virtual void drawLinearSliderThumb (Graphics& g, + int x, int y, + int width, int height, + float sliderPos, + float minSliderPos, + float maxSliderPos, + const Slider::SliderStyle style, + Slider& slider); + + virtual int getSliderThumbRadius (Slider& slider); + + virtual void drawRotarySlider (Graphics& g, + int x, int y, + int width, int height, + float sliderPosProportional, + const float rotaryStartAngle, + const float rotaryEndAngle, + Slider& slider); + + virtual Button* createSliderButton (const bool isIncrement); + virtual Label* createSliderTextBox (Slider& slider); + + virtual ImageEffectFilter* getSliderEffect(); + + virtual void getTooltipSize (const String& tipText, int& width, int& height); + + virtual void drawTooltip (Graphics& g, const String& text, int width, int height); + + virtual Button* createFilenameComponentBrowseButton (const String& text); + + virtual void layoutFilenameComponent (FilenameComponent& filenameComp, + ComboBox* filenameBox, Button* browseButton); + + virtual void drawCornerResizer (Graphics& g, + int w, int h, + bool isMouseOver, + bool isMouseDragging); + + virtual void drawResizableFrame (Graphics& g, + int w, int h, + const BorderSize& borders); + + virtual void fillResizableWindowBackground (Graphics& g, int w, int h, + const BorderSize& border, + ResizableWindow& window); + + virtual void drawResizableWindowBorder (Graphics& g, + int w, int h, + const BorderSize& border, + ResizableWindow& window); + + virtual void drawDocumentWindowTitleBar (DocumentWindow& window, + Graphics& g, int w, int h, + int titleSpaceX, int titleSpaceW, + const Image* icon, + bool drawTitleTextOnLeft); + + virtual Button* createDocumentWindowButton (int buttonType); + + virtual void positionDocumentWindowButtons (DocumentWindow& window, + int titleBarX, int titleBarY, + int titleBarW, int titleBarH, + Button* minimiseButton, + Button* maximiseButton, + Button* closeButton, + bool positionTitleBarButtonsOnLeft); + + virtual int getDefaultMenuBarHeight(); + + virtual DropShadower* createDropShadowerForComponent (Component* component); + + virtual void drawStretchableLayoutResizerBar (Graphics& g, + int w, int h, + bool isVerticalBar, + bool isMouseOver, + bool isMouseDragging); + + virtual void drawGroupComponentOutline (Graphics& g, int w, int h, + const String& text, + const Justification& position, + GroupComponent& group); + + virtual void createTabButtonShape (Path& p, + int width, int height, + int tabIndex, + const String& text, + Button& button, + TabbedButtonBar::Orientation orientation, + const bool isMouseOver, + const bool isMouseDown, + const bool isFrontTab); + + virtual void fillTabButtonShape (Graphics& g, + const Path& path, + const Colour& preferredBackgroundColour, + int tabIndex, + const String& text, + Button& button, + TabbedButtonBar::Orientation orientation, + const bool isMouseOver, + const bool isMouseDown, + const bool isFrontTab); + + virtual void drawTabButtonText (Graphics& g, + int x, int y, int w, int h, + const Colour& preferredBackgroundColour, + int tabIndex, + const String& text, + Button& button, + TabbedButtonBar::Orientation orientation, + const bool isMouseOver, + const bool isMouseDown, + const bool isFrontTab); + + virtual int getTabButtonOverlap (int tabDepth); + virtual int getTabButtonSpaceAroundImage(); + + virtual int getTabButtonBestWidth (int tabIndex, + const String& text, + int tabDepth, + Button& button); + + virtual void drawTabButton (Graphics& g, + int w, int h, + const Colour& preferredColour, + int tabIndex, + const String& text, + Button& button, + TabbedButtonBar::Orientation orientation, + const bool isMouseOver, + const bool isMouseDown, + const bool isFrontTab); + + virtual void drawTabAreaBehindFrontButton (Graphics& g, + int w, int h, + TabbedButtonBar& tabBar, + TabbedButtonBar::Orientation orientation); + + virtual Button* createTabBarExtrasButton(); + + virtual void drawImageButton (Graphics& g, Image* image, + int imageX, int imageY, int imageW, int imageH, + const Colour& overlayColour, + float imageOpacity, + ImageButton& button); + + virtual void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header); + + virtual void drawTableHeaderColumn (Graphics& g, const String& columnName, int columnId, + int width, int height, + bool isMouseOver, bool isMouseDown, + int columnFlags); + + virtual void paintToolbarBackground (Graphics& g, int width, int height, Toolbar& toolbar); + + virtual Button* createToolbarMissingItemsButton (Toolbar& toolbar); + + virtual void paintToolbarButtonBackground (Graphics& g, int width, int height, + bool isMouseOver, bool isMouseDown, + ToolbarItemComponent& component); + + virtual void paintToolbarButtonLabel (Graphics& g, int x, int y, int width, int height, + const String& text, ToolbarItemComponent& component); + + virtual void drawPropertyPanelSectionHeader (Graphics& g, const String& name, + bool isOpen, int width, int height); + + virtual void drawPropertyComponentBackground (Graphics& g, int width, int height, + PropertyComponent& component); + + virtual void drawPropertyComponentLabel (Graphics& g, int width, int height, + PropertyComponent& component); + + virtual const Rectangle getPropertyComponentContentPosition (PropertyComponent& component); + + virtual void drawLevelMeter (Graphics& g, int width, int height, float level); + + virtual void drawKeymapChangeButton (Graphics& g, int width, int height, Button& button, const String& keyDescription); + + /** + */ + virtual void playAlertSound(); + + /** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */ + static void drawGlassSphere (Graphics& g, + const float x, const float y, + const float diameter, + const Colour& colour, + const float outlineThickness) throw(); + + static void drawGlassPointer (Graphics& g, + const float x, const float y, + const float diameter, + const Colour& colour, const float outlineThickness, + const int direction) throw(); + + /** Utility function to draw a shiny, glassy oblong (for text buttons). */ + static void drawGlassLozenge (Graphics& g, + const float x, const float y, + const float width, const float height, + const Colour& colour, + const float outlineThickness, + const float cornerSize, + const bool flatOnLeft, const bool flatOnRight, + const bool flatOnTop, const bool flatOnBottom) throw(); + + juce_UseDebuggingNewOperator + +protected: + // xxx the following methods are only here to cause a compiler error, because they've been + // deprecated or their parameters have changed. Hopefully these definitions should cause an + // error if you try to build a subclass with the old versions. + virtual int drawTickBox (Graphics&, int, int, int, int, bool, const bool, const bool, const bool) { return 0; } + virtual int drawProgressBar (Graphics&, int, int, int, int, float) { return 0; } + virtual int drawProgressBar (Graphics&, ProgressBar&, int, int, int, int, float) { return 0; } + virtual void getTabButtonBestWidth (int, const String&, int) {} + virtual int drawTreeviewPlusMinusBox (Graphics&, int, int, int, int, bool) { return 0; } - class ButtonListenerProxy : public ButtonListener - { - public: - ButtonListenerProxy(); - void buttonClicked (Button* button); +private: + friend void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI(); + static void clearDefaultLookAndFeel() throw(); // called at shutdown - DocumentWindow* owner; + Array colourIds; + Array colours; - } buttonListener; + // default typeface names + String defaultSans, defaultSerif, defaultFixed; - void repaintTitleBar(); + void drawShinyButtonShape (Graphics& g, + float x, float y, float w, float h, float maxCornerSize, + const Colour& baseColour, + const float strokeWidth, + const bool flatOnLeft, + const bool flatOnRight, + const bool flatOnTop, + const bool flatOnBottom) throw(); - DocumentWindow (const DocumentWindow&); - const DocumentWindow& operator= (const DocumentWindow&); + LookAndFeel (const LookAndFeel&); + const LookAndFeel& operator= (const LookAndFeel&); }; -#endif // __JUCE_DOCUMENTWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_DocumentWindow.h *********/ +#endif // __JUCE_LOOKANDFEEL_JUCEHEADER__ +/********* End of inlined file: juce_LookAndFeel.h *********/ -class MultiDocumentPanel; -class MDITabbedComponentInternal; +#endif +#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ -/** - This is a derivative of DocumentWindow that is used inside a MultiDocumentPanel - component. +/********* Start of inlined file: juce_OldSchoolLookAndFeel.h *********/ +#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ +#define __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ - It's like a normal DocumentWindow but has some extra functionality to make sure - everything works nicely inside a MultiDocumentPanel. +/** + The original Juce look-and-feel. - @see MultiDocumentPanel */ -class JUCE_API MultiDocumentPanelWindow : public DocumentWindow +class JUCE_API OldSchoolLookAndFeel : public LookAndFeel { public: - /** - */ - MultiDocumentPanelWindow (const Colour& backgroundColour); + /** Creates the default JUCE look and feel. */ + OldSchoolLookAndFeel(); /** Destructor. */ - ~MultiDocumentPanelWindow(); + virtual ~OldSchoolLookAndFeel(); - /** @internal */ - void maximiseButtonPressed(); - /** @internal */ - void closeButtonPressed(); - /** @internal */ - void activeWindowStatusChanged(); - /** @internal */ - void broughtToFront(); + /** Draws the lozenge-shaped background for a standard button. */ + virtual void drawButtonBackground (Graphics& g, + Button& button, + const Colour& backgroundColour, + bool isMouseOverButton, + bool isButtonDown); - juce_UseDebuggingNewOperator + /** Draws the contents of a standard ToggleButton. */ + virtual void drawToggleButton (Graphics& g, + ToggleButton& button, + bool isMouseOverButton, + bool isButtonDown); -private: - void updateOrder(); - MultiDocumentPanel* getOwner() const throw(); -}; + virtual void drawTickBox (Graphics& g, + Component& component, + int x, int y, int w, int h, + const bool ticked, + const bool isEnabled, + const bool isMouseOverButton, + const bool isButtonDown); -/** - A component that contains a set of other components either in floating windows - or tabs. + virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar, + int width, int height, + double progress, const String& textToShow); - This acts as a panel that can be used to hold a set of open document windows, with - different layout modes. + virtual void drawScrollbarButton (Graphics& g, + ScrollBar& scrollbar, + int width, int height, + int buttonDirection, + bool isScrollbarVertical, + bool isMouseOverButton, + bool isButtonDown); - Use addDocument() and closeDocument() to add or remove components from the - panel - never use any of the Component methods to access the panel's child - components directly, as these are managed internally. -*/ -class JUCE_API MultiDocumentPanel : public Component, - private ComponentListener -{ -public: + virtual void drawScrollbar (Graphics& g, + ScrollBar& scrollbar, + int x, int y, + int width, int height, + bool isScrollbarVertical, + int thumbStartPosition, + int thumbSize, + bool isMouseOver, + bool isMouseDown); - /** Creates an empty panel. + virtual ImageEffectFilter* getScrollbarEffect(); - Use addDocument() and closeDocument() to add or remove components from the - panel - never use any of the Component methods to access the panel's child - components directly, as these are managed internally. - */ - MultiDocumentPanel(); + virtual void drawTextEditorOutline (Graphics& g, + int width, int height, + TextEditor& textEditor); - /** Destructor. + /** Fills the background of a popup menu component. */ + virtual void drawPopupMenuBackground (Graphics& g, int width, int height); - When deleted, this will call closeAllDocuments (false) to make sure all its - components are deleted. If you need to make sure all documents are saved - before closing, then you should call closeAllDocuments (true) and check that - it returns true before deleting the panel. - */ - ~MultiDocumentPanel(); + virtual void drawMenuBarBackground (Graphics& g, int width, int height, + bool isMouseOverBar, + MenuBarComponent& menuBar); - /** Tries to close all the documents. + virtual void drawComboBox (Graphics& g, int width, int height, + const bool isButtonDown, + int buttonX, int buttonY, + int buttonW, int buttonH, + ComboBox& box); - If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will - be called for each open document, and any of these calls fails, this method - will stop and return false, leaving some documents still open. + virtual const Font getComboBoxFont (ComboBox& box); - If checkItsOkToCloseFirst is false, then all documents will be closed - unconditionally. + virtual void drawLinearSlider (Graphics& g, + int x, int y, + int width, int height, + float sliderPos, + float minSliderPos, + float maxSliderPos, + const Slider::SliderStyle style, + Slider& slider); - @see closeDocument - */ - bool closeAllDocuments (const bool checkItsOkToCloseFirst); + virtual int getSliderThumbRadius (Slider& slider); - /** Adds a document component to the panel. + virtual Button* createSliderButton (const bool isIncrement); - If the number of documents would exceed the limit set by setMaximumNumDocuments() then - this will fail and return false. (If it does fail, the component passed-in will not be - deleted, even if deleteWhenRemoved was set to true). + virtual ImageEffectFilter* getSliderEffect(); - The MultiDocumentPanel will deal with creating a window border to go around your component, - so just pass in the bare content component here, no need to give it a ResizableWindow - or DocumentWindow. + virtual void drawCornerResizer (Graphics& g, + int w, int h, + bool isMouseOver, + bool isMouseDragging); - @param component the component to add - @param backgroundColour the background colour to use to fill the component's - window or tab - @param deleteWhenRemoved if true, then when the component is removed by closeDocument() - or closeAllDocuments(), then it will be deleted. If false, then - the caller must handle the component's deletion - */ - bool addDocument (Component* const component, - const Colour& backgroundColour, - const bool deleteWhenRemoved); + virtual Button* createDocumentWindowButton (int buttonType); - /** Closes one of the documents. + virtual void positionDocumentWindowButtons (DocumentWindow& window, + int titleBarX, int titleBarY, + int titleBarW, int titleBarH, + Button* minimiseButton, + Button* maximiseButton, + Button* closeButton, + bool positionTitleBarButtonsOnLeft); - If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will - be called, and if it fails, this method will return false without closing the - document. + juce_UseDebuggingNewOperator - If checkItsOkToCloseFirst is false, then the documents will be closed - unconditionally. +private: + DropShadowEffect scrollbarShadow; - The component will be deleted if the deleteWhenRemoved parameter was set to - true when it was added with addDocument. + OldSchoolLookAndFeel (const OldSchoolLookAndFeel&); + const OldSchoolLookAndFeel& operator= (const OldSchoolLookAndFeel&); +}; - @see addDocument, closeAllDocuments - */ - bool closeDocument (Component* component, - const bool checkItsOkToCloseFirst); +#endif // __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ +/********* End of inlined file: juce_OldSchoolLookAndFeel.h *********/ - /** Returns the number of open document windows. +#endif +#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__ - @see getDocument - */ - int getNumDocuments() const throw(); +#endif +#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__ - /** Returns one of the open documents. +#endif +#ifndef __JUCE_POPUPMENU_JUCEHEADER__ - The order of the documents in this array may change when they are added, removed - or moved around. +#endif +#ifndef __JUCE_POPUPMENUCUSTOMCOMPONENT_JUCEHEADER__ - @see getNumDocuments - */ - Component* getDocument (const int index) const throw(); +#endif +#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__ - /** Returns the document component that is currently focused or on top. +#endif +#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ - If currently using floating windows, then this will be the component in the currently - active window, or the top component if none are active. +#endif +#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ - If it's currently in tabbed mode, then it'll return the component in the active tab. +#endif +#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__ - @see setActiveDocument - */ - Component* getActiveDocument() const throw(); +#endif +#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__ - /** Makes one of the components active and brings it to the top. +/********* Start of inlined file: juce_LassoComponent.h *********/ +#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__ +#define __JUCE_LASSOCOMPONENT_JUCEHEADER__ - @see getActiveDocument - */ - void setActiveDocument (Component* component); +/********* Start of inlined file: juce_SelectedItemSet.h *********/ +#ifndef __JUCE_SELECTEDITEMSET_JUCEHEADER__ +#define __JUCE_SELECTEDITEMSET_JUCEHEADER__ - /** Callback which gets invoked when the currently-active document changes. */ - virtual void activeDocumentChanged(); +/** Manages a list of selectable items. - /** Sets a limit on how many windows can be open at once. + Use one of these to keep a track of things that the user has highlighted, like + icons or things in a list. - If this is zero or less there's no limit (the default). addDocument() will fail - if this number is exceeded. - */ - void setMaximumNumDocuments (const int maximumNumDocuments); + The class is templated so that you can use it to hold either a set of pointers + to objects, or a set of ID numbers or handles, for cases where each item may + not always have a corresponding object. - /** Sets an option to make the document fullscreen if there's only one document open. + To be informed when items are selected/deselected, register a ChangeListener with + this object. - If set to true, then if there's only one document, it'll fill the whole of this - component without tabs or a window border. If false, then tabs or a window - will always be shown, even if there's only one document. If there's more than - one document open, then this option makes no difference. - */ - void useFullscreenWhenOneDocument (const bool shouldUseTabs); + @see SelectableObject +*/ +template +class JUCE_API SelectedItemSet : public ChangeBroadcaster +{ +public: - /** Returns the result of the last time useFullscreenWhenOneDocument() was called. - */ - bool isFullscreenWhenOneDocument() const throw(); + /** Creates an empty set. */ + SelectedItemSet() + { + } - /** The different layout modes available. */ - enum LayoutMode + /** Creates a set based on an array of items. */ + SelectedItemSet (const Array & items) + : selectedItems (items) { - FloatingWindows, /**< In this mode, there are overlapping DocumentWindow components for each document. */ - MaximisedWindowsWithTabs /**< In this mode, a TabbedComponent is used to show one document at a time. */ - }; + } - /** Changes the panel's mode. + /** Creates a copy of another set. */ + SelectedItemSet (const SelectedItemSet& other) + : selectedItems (other.selectedItems) + { + } - @see LayoutMode, getLayoutMode - */ - void setLayoutMode (const LayoutMode newLayoutMode); + /** Creates a copy of another set. */ + const SelectedItemSet& operator= (const SelectedItemSet& other) + { + if (selectedItems != other.selectedItems) + { + selectedItems = other.selectedItems; + changed(); + } - /** Returns the current layout mode. */ - LayoutMode getLayoutMode() const throw() { return mode; } + return *this; + } - /** Sets the background colour for the whole panel. + /** Destructor. */ + ~SelectedItemSet() + { + } - Each document has its own background colour, but this is the one used to fill the areas - behind them. - */ - void setBackgroundColour (const Colour& newBackgroundColour); + /** Clears any other currently selected items, and selects this item. - /** Returns the current background colour. + If this item is already the only thing selected, no change notification + will be sent out. - @see setBackgroundColour + @see addToSelection, addToSelectionBasedOnModifiers */ - const Colour& getBackgroundColour() const throw() { return backgroundColour; } - - /** A subclass must override this to say whether its currently ok for a document - to be closed. - - This method is called by closeDocument() and closeAllDocuments() to indicate that - a document should be saved if possible, ready for it to be closed. - - If this method returns true, then it means the document is ok and can be closed. - - If it returns false, then it means that the closeDocument() method should stop - and not close. - - Normally, you'd use this method to ask the user if they want to save any changes, - then return true if the save operation went ok. If the user cancelled the save - operation you could return false here to abort the close operation. + void selectOnly (SelectableItemType item) + { + if (isSelected (item)) + { + for (int i = selectedItems.size(); --i >= 0;) + { + if (selectedItems.getUnchecked(i) != item) + { + deselect (selectedItems.getUnchecked(i)); + i = jmin (i, selectedItems.size()); + } + } + } + else + { + deselectAll(); + changed(); - If your component is based on the FileBasedDocument class, then you'd probably want - to call FileBasedDocument::saveIfNeededAndUserAgrees() and return true if this returned - FileBasedDocument::savedOk + selectedItems.add (item); + itemSelected (item); + } + } - @see closeDocument, FileBasedDocument::saveIfNeededAndUserAgrees() - */ - virtual bool tryToCloseDocument (Component* component) = 0; + /** Selects an item. - /** Creates a new window to be used for a document. + If the item is already selected, no change notification will be sent out. - The default implementation of this just returns a basic MultiDocumentPanelWindow object, - but you might want to override it to return a custom component. + @see selectOnly, addToSelectionBasedOnModifiers */ - virtual MultiDocumentPanelWindow* createNewDocumentWindow(); - - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void componentNameChanged (Component&); - - juce_UseDebuggingNewOperator - -private: - LayoutMode mode; - Array components; - TabbedComponent* tabComponent; - Colour backgroundColour; - int maximumNumDocuments, numDocsBeforeTabsUsed; - - friend class MultiDocumentPanelWindow; - friend class MDITabbedComponentInternal; - - Component* getContainerComp (Component* c) const; - void updateOrder(); - - void addWindow (Component* component); -}; - -#endif // __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__ -/********* End of inlined file: juce_MultiDocumentPanel.h *********/ - -#endif -#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ + void addToSelection (SelectableItemType item) + { + if (! isSelected (item)) + { + changed(); -#endif -#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ + selectedItems.add (item); + itemSelected (item); + } + } -#endif -#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ + /** Selects or deselects an item. -#endif -#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ + This will use the modifier keys to decide whether to deselect other items + first. -/********* Start of inlined file: juce_StretchableLayoutManager.h *********/ -#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ -#define __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ + So if the shift key is held down, the item will be added without deselecting + anything (same as calling addToSelection() ) -/** - For laying out a set of components, where the components have preferred sizes - and size limits, but where they are allowed to stretch to fill the available - space. + If no modifiers are down, the current selection will be cleared first (same + as calling selectOnly() ) - For example, if you have a component containing several other components, and - each one should be given a share of the total size, you could use one of these - to resize the child components when the parent component is resized. Then - you could add a StretchableLayoutResizerBar to easily let the user rescale them. + If the ctrl (or command on the Mac) key is held down, the item will be toggled - + so it'll be added to the set unless it's already there, in which case it'll be + deselected. - A StretchableLayoutManager operates only in one dimension, so if you have a set - of components stacked vertically on top of each other, you'd use one to manage their - heights. To build up complex arrangements of components, e.g. for applications - with multiple nested panels, you would use more than one StretchableLayoutManager. - E.g. by using two (one vertical, one horizontal), you could create a resizable - spreadsheet-style table. + If the items that you're selecting can also be dragged, you may need to use the + addToSelectionOnMouseDown() and addToSelectionOnMouseUp() calls to handle the + subtleties of this kind of usage. - E.g. - @code - class MyComp : public Component + @see selectOnly, addToSelection, addToSelectionOnMouseDown, addToSelectionOnMouseUp + */ + void addToSelectionBasedOnModifiers (SelectableItemType item, + const ModifierKeys& modifiers) { - StretchableLayoutManager myLayout; - - MyComp() + if (modifiers.isShiftDown()) { - myLayout.setItemLayout (0, // for item 0 - 50, 100, // must be between 50 and 100 pixels in size - -0.6); // and its preferred size is 60% of the total available space - - myLayout.setItemLayout (1, // for item 1 - -0.2, -0.6, // size must be between 20% and 60% of the available space - 50); // and its preferred size is 50 pixels + addToSelection (item); } - - void resized() + else if (modifiers.isCommandDown()) { - // make a list of two of our child components that we want to reposition - Component* comps[] = { myComp1, myComp2 }; - - // this will position the 2 components, one above the other, to fit - // vertically into the rectangle provided. - myLayout.layOutComponents (comps, 2, - 0, 0, getWidth(), getHeight(), - true); + if (isSelected (item)) + deselect (item); + else + addToSelection (item); } - }; - @endcode - - @see StretchableLayoutResizerBar -*/ -class JUCE_API StretchableLayoutManager -{ -public: + else + { + selectOnly (item); + } + } - /** Creates an empty layout. + /** Selects or deselects items that can also be dragged, based on a mouse-down event. - You'll need to add some item properties to the layout before it can be used - to resize things - see setItemLayout(). - */ - StretchableLayoutManager(); + If you call addToSelectionOnMouseDown() at the start of your mouseDown event, + and then call addToSelectionOnMouseUp() at the end of your mouseUp event, this + makes it easy to handle multiple-selection of sets of objects that can also + be dragged. - /** Destructor. */ - ~StretchableLayoutManager(); + For example, if you have several items already selected, and you click on + one of them (without dragging), then you'd expect this to deselect the other, and + just select the item you clicked on. But if you had clicked on this item and + dragged it, you'd have expected them all to stay selected. - /** For a numbered item, this sets its size limits and preferred size. + When you call this method, you'll need to store the boolean result, because the + addToSelectionOnMouseUp() method will need to be know this value. - @param itemIndex the index of the item to change. - @param minimumSize the minimum size that this item is allowed to be - a positive number - indicates an absolute size in pixels. A negative number indicates a - proportion of the available space (e.g -0.5 is 50%) - @param maximumSize the maximum size that this item is allowed to be - a positive number - indicates an absolute size in pixels. A negative number indicates a - proportion of the available space - @param preferredSize the size that this item would like to be, if there's enough room. A - positive number indicates an absolute size in pixels. A negative number - indicates a proportion of the available space - @see getItemLayout + @see addToSelectionOnMouseUp, addToSelectionBasedOnModifiers */ - void setItemLayout (const int itemIndex, - const double minimumSize, - const double maximumSize, - const double preferredSize); + bool addToSelectionOnMouseDown (SelectableItemType item, + const ModifierKeys& modifiers) + { + if (isSelected (item)) + { + return ! modifiers.isPopupMenu(); + } + else + { + addToSelectionBasedOnModifiers (item, modifiers); + return false; + } + } - /** For a numbered item, this returns its size limits and preferred size. + /** Selects or deselects items that can also be dragged, based on a mouse-up event. - @param itemIndex the index of the item. - @param minimumSize the minimum size that this item is allowed to be - a positive number - indicates an absolute size in pixels. A negative number indicates a - proportion of the available space (e.g -0.5 is 50%) - @param maximumSize the maximum size that this item is allowed to be - a positive number - indicates an absolute size in pixels. A negative number indicates a - proportion of the available space - @param preferredSize the size that this item would like to be, if there's enough room. A - positive number indicates an absolute size in pixels. A negative number - indicates a proportion of the available space - @returns false if the item's properties hadn't been set - @see setItemLayout - */ - bool getItemLayout (const int itemIndex, - double& minimumSize, - double& maximumSize, - double& preferredSize) const; + Call this during a mouseUp callback, when you have previously called the + addToSelectionOnMouseDown() method during your mouseDown event. - /** Clears all the properties that have been set with setItemLayout() and resets - this object to its initial state. + See addToSelectionOnMouseDown() for more info + + @param item the item to select (or deselect) + @param modifiers the modifiers from the mouse-up event + @param wasItemDragged true if your item was dragged during the mouse click + @param resultOfMouseDownSelectMethod this is the boolean return value that came + back from the addToSelectionOnMouseDown() call that you + should have made during the matching mouseDown event */ - void clearAllItems(); + void addToSelectionOnMouseUp (SelectableItemType item, + const ModifierKeys& modifiers, + const bool wasItemDragged, + const bool resultOfMouseDownSelectMethod) + { + if (resultOfMouseDownSelectMethod && ! wasItemDragged) + addToSelectionBasedOnModifiers (item, modifiers); + } - /** Takes a set of components that correspond to the layout's items, and positions - them to fill a space. + /** Deselects an item. */ + void deselect (SelectableItemType item) + { + const int i = selectedItems.indexOf (item); - This will try to give each item its preferred size, whether that's a relative size - or an absolute one. + if (i >= 0) + { + changed(); + itemDeselected (selectedItems.remove (i)); + } + } - @param components an array of components that correspond to each of the - numbered items that the StretchableLayoutManager object - has been told about with setItemLayout() - @param numComponents the number of components in the array that is passed-in. This - should be the same as the number of items this object has been - told about. - @param x the left of the rectangle in which the components should - be laid out - @param y the top of the rectangle in which the components should - be laid out - @param width the width of the rectangle in which the components should - be laid out - @param height the height of the rectangle in which the components should - be laid out - @param vertically if true, the components will be positioned in a vertical stack, - so that they fill the height of the rectangle. If false, they - will be placed side-by-side in a horizontal line, filling the - available width - @param resizeOtherDimension if true, this means that the components will have their - other dimension resized to fit the space - i.e. if the 'vertically' - parameter is true, their x-positions and widths are adjusted to fit - the x and width parameters; if 'vertically' is false, their y-positions - and heights are adjusted to fit the y and height parameters. - */ - void layOutComponents (Component** const components, - int numComponents, - int x, int y, int width, int height, - const bool vertically, - const bool resizeOtherDimension); + /** Deselects all items. */ + void deselectAll() + { + if (selectedItems.size() > 0) + { + changed(); - /** Returns the current position of one of the items. + for (int i = selectedItems.size(); --i >= 0;) + { + itemDeselected (selectedItems.remove (i)); + i = jmin (i, selectedItems.size()); + } + } + } - This is only a valid call after layOutComponents() has been called, as it - returns the last position that this item was placed at. If the layout was - vertical, the value returned will be the y position of the top of the item, - relative to the top of the rectangle in which the items were placed (so for - example, item 0 will always have position of 0, even in the rectangle passed - in to layOutComponents() wasn't at y = 0). If the layout was done horizontally, - the position returned is the item's left-hand position, again relative to the - x position of the rectangle used. + /** Returns the number of currently selected items. - @see getItemCurrentSize, setItemPosition + @see getSelectedItem */ - int getItemCurrentPosition (const int itemIndex) const; + int getNumSelected() const throw() + { + return selectedItems.size(); + } - /** Returns the current size of one of the items. + /** Returns one of the currently selected items. - This is only meaningful after layOutComponents() has been called, as it - returns the last size that this item was given. If the layout was done - vertically, it'll return the item's height in pixels; if it was horizontal, - it'll return its width. + Returns 0 if the index is out-of-range. - @see getItemCurrentRelativeSize + @see getNumSelected */ - int getItemCurrentAbsoluteSize (const int itemIndex) const; + SelectableItemType getSelectedItem (const int index) const throw() + { + return selectedItems [index]; + } - /** Returns the current size of one of the items. + /** True if this item is currently selected. */ + bool isSelected (const SelectableItemType item) const throw() + { + return selectedItems.contains (item); + } - This is only meaningful after layOutComponents() has been called, as it - returns the last size that this item was given. If the layout was done - vertically, it'll return a negative value representing the item's height relative - to the last size used for laying the components out; if the layout was done - horizontally it'll be the proportion of its width. + const Array & getItemArray() const throw() { return selectedItems; } - @see getItemCurrentAbsoluteSize - */ - double getItemCurrentRelativeSize (const int itemIndex) const; + /** Can be overridden to do special handling when an item is selected. - /** Moves one of the items, shifting along any other items as necessary in - order to get it to the desired position. + For example, if the item is an object, you might want to call it and tell + it that it's being selected. + */ + virtual void itemSelected (SelectableItemType item) {} - Calling this method will also update the preferred sizes of the items it - shuffles along, so that they reflect their new positions. + /** Can be overridden to do special handling when an item is deselected. - (This is the method that a StretchableLayoutResizerBar uses to shift the items - about when it's dragged). + For example, if the item is an object, you might want to call it and tell + it that it's being deselected. + */ + virtual void itemDeselected (SelectableItemType item) {} - @param itemIndex the item to move - @param newPosition the absolute position that you'd like this item to move - to. The item might not be able to always reach exactly this position, - because other items may have minimum sizes that constrain how - far it can go + /** Used internally, but can be called to force a change message to be sent to the ChangeListeners. */ - void setItemPosition (const int itemIndex, - int newPosition); + void changed (const bool synchronous = false) + { + if (synchronous) + sendSynchronousChangeMessage (this); + else + sendChangeMessage (this); + } juce_UseDebuggingNewOperator private: - struct ItemLayoutProperties - { - int itemIndex; - int currentSize; - double minSize, maxSize, preferredSize; - }; + Array selectedItems; +}; - OwnedArray items; - int totalSize; +#endif // __JUCE_SELECTEDITEMSET_JUCEHEADER__ +/********* End of inlined file: juce_SelectedItemSet.h *********/ - static int sizeToRealSize (double size, int totalSpace); +/** + A class used by the LassoComponent to manage the things that it selects. - ItemLayoutProperties* getInfoFor (const int itemIndex) const; + This allows the LassoComponent to find out which items are within the lasso, + and to change the list of selected items. - void setTotalSize (const int newTotalSize); + @see LassoComponent, SelectedItemSet +*/ +template +class LassoSource +{ +public: + /** Destructor. */ + virtual ~LassoSource() {} - int fitComponentsIntoSpace (const int startIndex, - const int endIndex, - const int availableSpace, - int startPos); + /** Returns the set of items that lie within a given lassoable region. - int getMinimumSizeOfItems (const int startIndex, const int endIndex) const; - int getMaximumSizeOfItems (const int startIndex, const int endIndex) const; + Your implementation of this method must find all the relevent items that lie + within the given rectangle. and add them to the itemsFound array. - void updatePrefSizesToMatchCurrentPositions(); + The co-ordinates are relative to the top-left of the lasso component's parent + component. (i.e. they are the same as the size and position of the lasso + component itself). + */ + virtual void findLassoItemsInArea (Array & itemsFound, + int x, int y, int width, int height) = 0; - StretchableLayoutManager (const StretchableLayoutManager&); - const StretchableLayoutManager& operator= (const StretchableLayoutManager&); + /** Returns the SelectedItemSet that the lasso should update. + + This set will be continuously updated by the LassoComponent as it gets + dragged around, so make sure that you've got a ChangeListener attached to + the set so that your UI objects will know when the selection changes and + be able to update themselves appropriately. + */ + virtual SelectedItemSet & getLassoSelection() = 0; }; -#endif // __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ -/********* End of inlined file: juce_StretchableLayoutManager.h *********/ +/** + A component that acts as a rectangular selection region, which you drag with + the mouse to select groups of objects (in conjunction with a SelectedItemSet). -#endif -#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ + To use one of these: -/********* Start of inlined file: juce_StretchableLayoutResizerBar.h *********/ -#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ -#define __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ + - In your mouseDown or mouseDrag event, add the LassoComponent to your parent + component, and call its beginLasso() method, giving it a + suitable LassoSource object that it can use to find out which items are in + the active area. -/** - A component that acts as one of the vertical or horizontal bars you see being - used to resize panels in a window. + - Each time your parent component gets a mouseDrag event, call dragLasso() + to update the lasso's position - it will use its LassoSource to calculate and + update the current selection. - One of these acts with a StretchableLayoutManager to resize the other components. + - After the drag has finished and you get a mouseUp callback, you should call + endLasso() to clean up. This will make the lasso component invisible, and you + can remove it from the parent component, or delete it. - @see StretchableLayoutManager + The class takes into account the modifier keys that are being held down while + the lasso is being dragged, so if shift is pressed, then any lassoed items will + be added to the original selection; if ctrl or command is pressed, they will be + xor'ed with any previously selected items. + + @see LassoSource, SelectedItemSet */ -class JUCE_API StretchableLayoutResizerBar : public Component +template +class LassoComponent : public Component { public: - /** Creates a resizer bar for use on a specified layout. + /** Creates a Lasso component. - @param layoutToUse the layout that will be affected when this bar - is dragged - @param itemIndexInLayout the item index in the layout that corresponds to - this bar component. You'll need to set up the item - properties in a suitable way for a divider bar, e.g. - for an 8-pixel wide bar which, you could call - myLayout->setItemLayout (barIndex, 8, 8, 8) - @param isBarVertical true if it's an upright bar that you drag left and - right; false for a horizontal one that you drag up and - down + The fill colour is used to fill the lasso'ed rectangle, and the outline + colour is used to draw a line around its edge. */ - StretchableLayoutResizerBar (StretchableLayoutManager* const layoutToUse, - const int itemIndexInLayout, - const bool isBarVertical); + LassoComponent (const int outlineThickness_ = 1) + : source (0), + outlineThickness (outlineThickness_) + { + } /** Destructor. */ - ~StretchableLayoutResizerBar(); + ~LassoComponent() + { + } - /** This is called when the bar is dragged. + /** Call this in your mouseDown event, to initialise a drag. - This method must update the positions of any components whose position is - determined by the StretchableLayoutManager, because they might have just - moved. + Pass in a suitable LassoSource object which the lasso will use to find + the items and change the selection. - The default implementation calls the resized() method of this component's - parent component, because that's often where you're likely to apply the - layout, but it can be overridden for more specific needs. - */ - virtual void hasBeenMoved(); + After using this method to initialise the lasso, repeatedly call dragLasso() + in your component's mouseDrag callback. - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); + @see dragLasso, endLasso, LassoSource + */ + void beginLasso (const MouseEvent& e, + LassoSource * const lassoSource) + { + jassert (source == 0); // this suggests that you didn't call endLasso() after the last drag... + jassert (lassoSource != 0); // the source can't be null! + jassert (getParentComponent() != 0); // you need to add this to a parent component for it to work! - juce_UseDebuggingNewOperator + source = lassoSource; -private: - StretchableLayoutManager* layout; - int itemIndex, mouseDownPos; - bool isVertical; + if (lassoSource != 0) + originalSelection = lassoSource->getLassoSelection().getItemArray(); - StretchableLayoutResizerBar (const StretchableLayoutResizerBar&); - const StretchableLayoutResizerBar& operator= (const StretchableLayoutResizerBar&); -}; + setSize (0, 0); + } -#endif // __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ -/********* End of inlined file: juce_StretchableLayoutResizerBar.h *********/ + /** Call this in your mouseDrag event, to update the lasso's position. -#endif -#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ + This must be repeatedly calling when the mouse is dragged, after you've + first initialised the lasso with beginLasso(). -/********* Start of inlined file: juce_StretchableObjectResizer.h *********/ -#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ -#define __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ + This method takes into account the modifier keys that are being held down, so + if shift is pressed, then the lassoed items will be added to any that were + previously selected; if ctrl or command is pressed, then they will be xor'ed + with previously selected items. -/** - A utility class for fitting a set of objects whose sizes can vary between - a minimum and maximum size, into a space. + @see beginLasso, endLasso + */ + void dragLasso (const MouseEvent& e) + { + if (source != 0) + { + const int x1 = e.getMouseDownX(); + const int y1 = e.getMouseDownY(); - This is a trickier algorithm than it would first seem, so I've put it in this - class to allow it to be shared by various bits of code. + setBounds (jmin (x1, e.x), jmin (y1, e.y), abs (e.x - x1), abs (e.y - y1)); + setVisible (true); - To use it, create one of these objects, call addItem() to add the list of items - you need, then call resizeToFit(), which will change all their sizes. You can - then retrieve the new sizes with getItemSize() and getNumItems(). + Array itemsInLasso; + source->findLassoItemsInArea (itemsInLasso, getX(), getY(), getWidth(), getHeight()); - It's currently used by the TableHeaderComponent for stretching out the table - headings to fill the table's width. -*/ -class StretchableObjectResizer -{ -public: + if (e.mods.isShiftDown()) + { + itemsInLasso.removeValuesIn (originalSelection); // to avoid duplicates + itemsInLasso.addArray (originalSelection); + } + else if (e.mods.isCommandDown() || e.mods.isAltDown()) + { + Array originalMinusNew (originalSelection); + originalMinusNew.removeValuesIn (itemsInLasso); - /** Creates an empty object resizer. */ - StretchableObjectResizer(); + itemsInLasso.removeValuesIn (originalSelection); + itemsInLasso.addArray (originalMinusNew); + } - /** Destructor. */ - ~StretchableObjectResizer(); + source->getLassoSelection() = SelectedItemSet (itemsInLasso); + } + } - /** Adds an item to the list. + /** Call this in your mouseUp event, after the lasso has been dragged. - The order parameter lets you specify groups of items that are resized first when some - space needs to be found. Those items with an order of 0 will be the first ones to be - resized, and if that doesn't provide enough space to meet the requirements, the algorithm - will then try resizing the items with an order of 1, then 2, and so on. + @see beginLasso, dragLasso */ - void addItem (const double currentSize, - const double minSize, - const double maxSize, - const int order = 0); + void endLasso() + { + source = 0; + originalSelection.clear(); + setVisible (false); + } - /** Resizes all the items to fit this amount of space. + /** A set of colour IDs to use to change the colour of various aspects of the label. - This will attempt to fit them in without exceeding each item's miniumum and - maximum sizes. In cases where none of the items can be expanded or enlarged any - further, the final size may be greater or less than the size passed in. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - After calling this method, you can retrieve the new sizes with the getItemSize() - method. - */ - void resizeToFit (const double targetSize); + Note that you can also use the constants from TextEditor::ColourIds to change the + colour of the text editor that is opened when a label is editable. - /** Returns the number of items that have been added. */ - int getNumItems() const throw() { return items.size(); } + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + lassoFillColourId = 0x1000440, /**< The colour to fill the lasso rectangle with. */ + lassoOutlineColourId = 0x1000441, /**< The colour to draw the outline with. */ + }; - /** Returns the size of one of the items. */ - double getItemSize (const int index) const throw(); + /** @internal */ + void paint (Graphics& g) + { + g.fillAll (findColour (lassoFillColourId)); - juce_UseDebuggingNewOperator + g.setColour (findColour (lassoOutlineColourId)); + g.drawRect (0, 0, getWidth(), getHeight(), outlineThickness); -private: - struct Item - { - double size; - double minSize; - double maxSize; - int order; - }; + // this suggests that you've left a lasso comp lying around after the + // mouse drag has finished.. Be careful to call endLasso() when you get a + // mouse-up event. + jassert (isMouseButtonDownAnywhere()); + } - OwnedArray items; + /** @internal */ + bool hitTest (int x, int y) { return false; } - StretchableObjectResizer (const StretchableObjectResizer&); - const StretchableObjectResizer& operator= (const StretchableObjectResizer&); -}; + juce_UseDebuggingNewOperator -#endif // __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ -/********* End of inlined file: juce_StretchableObjectResizer.h *********/ +private: + Array originalSelection; + LassoSource * source; + int outlineThickness; +}; -#endif -#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__ +#endif // __JUCE_LASSOCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_LassoComponent.h *********/ #endif -#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_MOUSECURSOR_JUCEHEADER__ #endif -#ifndef __JUCE_VIEWPORT_JUCEHEADER__ +#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__ #endif -#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ - -/********* Start of inlined file: juce_DirectoryContentsDisplayComponent.h *********/ -#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ -#define __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ - -/********* Start of inlined file: juce_DirectoryContentsList.h *********/ -#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ -#define __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ +#ifndef __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ -/********* Start of inlined file: juce_FileFilter.h *********/ -#ifndef __JUCE_FILEFILTER_JUCEHEADER__ -#define __JUCE_FILEFILTER_JUCEHEADER__ +/********* Start of inlined file: juce_MouseHoverDetector.h *********/ +#ifndef __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ +#define __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ /** - Interface for deciding which files are suitable for something. + Monitors a component for mouse activity, and triggers a callback + when the mouse hovers in one place for a specified length of time. - For example, this is used by DirectoryContentsList to select which files - go into the list. + To use a hover-detector, just create one and call its setHoverComponent() + method to start it watching a component. You can call setHoverComponent (0) + to make it inactive. - @see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent + (Be careful not to delete a component that's being monitored without first + stopping or deleting the hover detector). */ -class JUCE_API FileFilter +class JUCE_API MouseHoverDetector { public: - /** Creates a filter with the given description. + /** Creates a hover detector. - The description can be returned later with the getDescription() method. + Initially the object is inactive, and you need to tell it which component + to monitor, using the setHoverComponent() method. + + @param hoverTimeMillisecs the number of milliseconds for which the mouse + needs to stay still before the mouseHovered() method + is invoked. You can change this setting later with + the setHoverTimeMillisecs() method */ - FileFilter (const String& filterDescription); + MouseHoverDetector (const int hoverTimeMillisecs = 400); /** Destructor. */ - virtual ~FileFilter(); - - /** Returns the description that the filter was created with. */ - const String& getDescription() const throw(); + virtual ~MouseHoverDetector(); - /** Should return true if this file is suitable for inclusion in whatever context - the object is being used. + /** Changes the time for which the mouse has to stay still before it's considered + to be hovering. */ - virtual bool isFileSuitable (const File& file) const = 0; + void setHoverTimeMillisecs (const int newTimeInMillisecs); - /** Should return true if this directory is suitable for inclusion in whatever context - the object is being used. + /** Changes the component that's being monitored for hovering. + + Be careful not to delete a component that's being monitored without first + stopping or deleting the hover detector. */ - virtual bool isDirectorySuitable (const File& file) const = 0; + void setHoverComponent (Component* const newSourceComponent); protected: - String description; -}; - -#endif // __JUCE_FILEFILTER_JUCEHEADER__ -/********* End of inlined file: juce_FileFilter.h *********/ - -/** - A class to asynchronously scan for details about the files in a directory. + /** Called back when the mouse hovers. - This keeps a list of files and some information about them, using a background - thread to scan for more files. As files are found, it broadcasts change messages - to tell any listeners. + After the mouse has stayed still over the component for the length of time + specified by setHoverTimeMillisecs(), this method will be invoked. - @see FileListComponent, FileBrowserComponent -*/ -class JUCE_API DirectoryContentsList : public ChangeBroadcaster, - public TimeSliceClient -{ -public: + When the mouse is first moved after this callback has occurred, the + mouseMovedAfterHover() method will be called. - /** Creates a directory list. + @param mouseX the mouse's X position relative to the component being monitored + @param mouseY the mouse's Y position relative to the component being monitored + */ + virtual void mouseHovered (int mouseX, + int mouseY) = 0; - To set the directory it should point to, use setDirectory(), which will - also start it scanning for files on the background thread. + /** Called when the mouse is moved away after just having hovered. */ + virtual void mouseMovedAfterHover() = 0; - When the background thread finds and adds new files to this list, the - ChangeBroadcaster class will send a change message, so you can register - listeners and update them when the list changes. +private: - @param fileFilter an optional filter to select which files are - included in the list. If this is 0, then all files - and directories are included. Make sure that the - filter doesn't get deleted during the lifetime of this - object - @param threadToUse a thread object that this list can use - to scan for files as a background task. Make sure - that the thread you give it has been started, or you - won't get any files! - */ - DirectoryContentsList (const FileFilter* const fileFilter, - TimeSliceThread& threadToUse); + class JUCE_API HoverDetectorInternal : public MouseListener, + public Timer + { + public: + MouseHoverDetector* owner; + int lastX, lastY; - /** Destructor. */ - ~DirectoryContentsList(); + void timerCallback(); + void mouseEnter (const MouseEvent&); + void mouseExit (const MouseEvent&); + void mouseDown (const MouseEvent&); + void mouseUp (const MouseEvent&); + void mouseMove (const MouseEvent&); + void mouseWheelMove (const MouseEvent&, float, float); - /** Sets the directory to look in for files. + } internalTimer; - If the directory that's passed in is different to the current one, this will - also start the background thread scanning it for files. - */ - void setDirectory (const File& directory, - const bool includeDirectories, - const bool includeFiles); + friend class HoverDetectorInternal; - /** Returns the directory that's currently being used. */ - const File& getDirectory() const throw(); + Component* source; + int hoverTimeMillisecs; + bool hasJustHovered; - /** Clears the list, and stops the thread scanning for files. */ - void clear(); + void hoverTimerCallback(); + void checkJustHoveredCallback(); +}; - /** Clears the list and restarts scanning the directory for files. */ - void refresh(); +#endif // __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__ +/********* End of inlined file: juce_MouseHoverDetector.h *********/ - /** True if the background thread hasn't yet finished scanning for files. */ - bool isStillLoading() const; +#endif +#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__ - /** Tells the list whether or not to ignore hidden files. +#endif +#ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ - By default these are ignored. - */ - void setIgnoresHiddenFiles (const bool shouldIgnoreHiddenFiles); +#endif +#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ - /** Returns true if hidden files are ignored. - @see setIgnoresHiddenFiles - */ - bool ignoresHiddenFiles() const throw() { return ignoreHiddenFiles; } +/********* Start of inlined file: juce_BooleanPropertyComponent.h *********/ +#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ - /** Contains cached information about one of the files in a DirectoryContentsList. - */ - struct FileInfo - { +/** + A PropertyComponent that contains an on/off toggle button. - /** The filename. + This type of property component can be used if you have a boolean value to + toggle on/off. - This isn't a full pathname, it's just the last part of the path, same as you'd - get from File::getFileName(). + @see PropertyComponent +*/ +class JUCE_API BooleanPropertyComponent : public PropertyComponent, + private ButtonListener +{ +public: - To get the full pathname, use DirectoryContentsList::getDirectory().getChildFile (filename). - */ - String filename; + /** Creates a button component. - /** File size in bytes. */ - int64 fileSize; + @param propertyName the property name to be passed to the PropertyComponent + @param buttonTextWhenTrue the text shown in the button when the value is true + @param buttonTextWhenFalse the text shown in the button when the value is false + */ + BooleanPropertyComponent (const String& propertyName, + const String& buttonTextWhenTrue, + const String& buttonTextWhenFalse); - /** File modification time. + /** Destructor. */ + ~BooleanPropertyComponent(); - As supplied by File::getLastModificationTime(). - */ - Time modificationTime; + /** Called to change the state of the boolean value. */ + virtual void setState (const bool newState) = 0; - /** File creation time. + /** Must return the current value of the property. */ + virtual bool getState() const = 0; - As supplied by File::getCreationTime(). - */ - Time creationTime; + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void refresh(); + /** @internal */ + void buttonClicked (Button*); - /** True if the file is a directory. */ - bool isDirectory; + juce_UseDebuggingNewOperator - /** True if the file is read-only. */ - bool isReadOnly; - }; +private: + ToggleButton* button; + String onText, offText; +}; - /** Returns the number of files currently available in the list. +#endif // __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_BooleanPropertyComponent.h *********/ - The info about one of these files can be retrieved with getFileInfo() or - getFile(). +#endif +#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ - Obviously as the background thread runs and scans the directory for files, this - number will change. +/********* Start of inlined file: juce_ButtonPropertyComponent.h *********/ +#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ - @see getFileInfo, getFile - */ - int getNumFiles() const; +/** + A PropertyComponent that contains a button. - /** Returns the cached information about one of the files in the list. + This type of property component can be used if you need a button to trigger some + kind of action. - If the index is in-range, this will return true and will copy the file's details - to the structure that is passed-in. + @see PropertyComponent +*/ +class JUCE_API ButtonPropertyComponent : public PropertyComponent, + private ButtonListener +{ +public: - If it returns false, then the index wasn't in range, and the structure won't - be affected. + /** Creates a button component. - @see getNumFiles, getFile + @param propertyName the property name to be passed to the PropertyComponent + @param triggerOnMouseDown this is passed to the Button::setTriggeredOnMouseDown() method */ - bool getFileInfo (const int index, - FileInfo& resultInfo) const; + ButtonPropertyComponent (const String& propertyName, + const bool triggerOnMouseDown); - /** Returns one of the files in the list. + /** Destructor. */ + ~ButtonPropertyComponent(); - @param index should be less than getNumFiles(). If this is out-of-range, the - return value will be File::nonexistent - @see getNumFiles, getFileInfo + /** Called when the user clicks the button. */ - const File getFile (const int index) const; + virtual void buttonClicked() = 0; - /** Returns the file filter being used. + /** Returns the string that should be displayed in the button. - The filter is specified in the constructor. + If you need to change this string, call refresh() to update the component. */ - const FileFilter* getFilter() const throw() { return fileFilter; } + virtual const String getButtonText() const = 0; /** @internal */ - bool useTimeSlice(); - /** @internal */ - TimeSliceThread& getTimeSliceThread() throw() { return thread; } + void refresh(); /** @internal */ - static int compareElements (const DirectoryContentsList::FileInfo* const first, - const DirectoryContentsList::FileInfo* const second) throw(); + void buttonClicked (Button*); juce_UseDebuggingNewOperator private: - File root; - const FileFilter* fileFilter; - TimeSliceThread& thread; - bool includeDirectories, includeFiles, ignoreHiddenFiles; + TextButton* button; +}; - CriticalSection fileListLock; - OwnedArray files; +#endif // __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ButtonPropertyComponent.h *********/ - void* volatile fileFindHandle; - bool volatile shouldStop; +#endif +#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ - void changed(); - bool checkNextFile (bool& hasChanged); - bool addFile (const String& filename, const bool isDir, const bool isHidden, - const int64 fileSize, const Time& modTime, - const Time& creationTime, const bool isReadOnly); +/********* Start of inlined file: juce_ChoicePropertyComponent.h *********/ +#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ - DirectoryContentsList (const DirectoryContentsList&); - const DirectoryContentsList& operator= (const DirectoryContentsList&); -}; +/** + A PropertyComponent that shows its value as a combo box. -#endif // __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ -/********* End of inlined file: juce_DirectoryContentsList.h *********/ + This type of property component contains a list of options and has a + combo box to choose one. -/********* Start of inlined file: juce_FileBrowserListener.h *********/ -#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ -#define __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ + Your subclass's constructor must add some strings to the choices StringArray + and these are shown in the list. -/** - A listener for user selection events in a file browser. + The getIndex() method will be called to find out which option is the currently + selected one. If you call refresh() it will call getIndex() to check whether + the value has changed, and will update the combo box if needed. - This is used by a FileBrowserComponent or FileListComponent. + If the user selects a different item from the list, setIndex() will be + called to let your class process this. + + @see PropertyComponent, PropertyPanel */ -class JUCE_API FileBrowserListener +class JUCE_API ChoicePropertyComponent : public PropertyComponent, + private ComboBoxListener { public: + /** Creates the component. + + Your subclass's constructor must add a list of options to the choices + member variable. + */ + ChoicePropertyComponent (const String& propertyName); /** Destructor. */ - virtual ~FileBrowserListener(); + ~ChoicePropertyComponent(); - /** Callback when the user selects a different file in the browser. */ - virtual void selectionChanged() = 0; + /** Called when the user selects an item from the combo box. - /** Callback when the user clicks on a file in the browser. */ - virtual void fileClicked (const File& file, const MouseEvent& e) = 0; + Your subclass must use this callback to update the value that this component + represents. The index is the index of the chosen item in the choices + StringArray. + */ + virtual void setIndex (const int newIndex) = 0; - /** Callback when the user double-clicks on a file in the browser. */ - virtual void fileDoubleClicked (const File& file) = 0; -}; + /** Returns the index of the item that should currently be shown. -#endif // __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ -/********* End of inlined file: juce_FileBrowserListener.h *********/ + This is the index of the item in the choices StringArray that will be + shown. + */ + virtual int getIndex() const = 0; -/** - A base class for components that display a list of the files in a directory. + /** Returns the list of options. */ + const StringArray& getChoices() const throw(); - @see DirectoryContentsList -*/ -class JUCE_API DirectoryContentsDisplayComponent -{ -public: + /** @internal */ + void refresh(); + /** @internal */ + void comboBoxChanged (ComboBox*); - /** - */ - DirectoryContentsDisplayComponent (DirectoryContentsList& listToShow); + juce_UseDebuggingNewOperator - /** Destructor. */ - virtual ~DirectoryContentsDisplayComponent(); +protected: + /** The list of options that will be shown in the combo box. - /** Returns the number of files the user has got selected. - @see getSelectedFile + Your subclass must populate this array in its constructor. If any empty + strings are added, these will be replaced with horizontal separators (see + ComboBox::addSeparator() for more info). */ - virtual int getNumSelectedFiles() const = 0; + StringArray choices; - /** Returns one of the files that the user has currently selected. - The index should be in the range 0 to (getNumSelectedFiles() - 1). - @see getNumSelectedFiles - */ - virtual const File getSelectedFile (int index) const = 0; +private: + ComboBox* comboBox; +}; - /** Scrolls this view to the top. */ - virtual void scrollToTop() = 0; +#endif // __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ChoicePropertyComponent.h *********/ - /** Adds a listener to be told when files are selected or clicked. +#endif +#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ - @see removeListener - */ - void addListener (FileBrowserListener* const listener) throw(); +#endif +#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ - /** Removes a listener. +#endif +#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ - @see addListener - */ - void removeListener (FileBrowserListener* const listener) throw(); +/********* Start of inlined file: juce_SliderPropertyComponent.h *********/ +#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ - /** A set of colour IDs to use to change the colour of various aspects of the label. +/** + A PropertyComponent that shows its value as a slider. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + @see PropertyComponent, Slider +*/ +class JUCE_API SliderPropertyComponent : public PropertyComponent, + private SliderListener +{ +public: - Note that you can also use the constants from TextEditor::ColourIds to change the - colour of the text editor that is opened when a label is editable. + /** Creates the property component. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + The ranges, interval and skew factor are passed to the Slider component. + + If you need to customise the slider in other ways, your constructor can + access the slider member variable and change it directly. */ - enum ColourIds - { - highlightColourId = 0x1000540, /**< The colour to use to fill a highlighted row of the list. */ - textColourId = 0x1000541, /**< The colour for the text. */ - }; + SliderPropertyComponent (const String& propertyName, + const double rangeMin, + const double rangeMax, + const double interval, + const double skewFactor = 1.0); + + /** Destructor. */ + ~SliderPropertyComponent(); + + /** Called when the user moves the slider to change its value. + + Your subclass must use this method to update whatever item this property + represents. + */ + virtual void setValue (const double newValue) = 0; + + /** Returns the value that the slider should show. */ + virtual const double getValue() const = 0; /** @internal */ - void sendSelectionChangeMessage(); + void refresh(); /** @internal */ - void sendDoubleClickMessage (const File& file); + void changeListenerCallback (void*); /** @internal */ - void sendMouseClickMessage (const File& file, const MouseEvent& e); + void sliderValueChanged (Slider*); juce_UseDebuggingNewOperator protected: - DirectoryContentsList& fileList; - SortedSet listeners; - - DirectoryContentsDisplayComponent (const DirectoryContentsDisplayComponent&); - const DirectoryContentsDisplayComponent& operator= (const DirectoryContentsDisplayComponent&); -}; -#endif // __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_DirectoryContentsDisplayComponent.h *********/ + /** The slider component being used in this component. -#endif -#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ + Your subclass has access to this in case it needs to customise it in some way. + */ + Slider* slider; +}; -#endif -#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ +#endif // __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_SliderPropertyComponent.h *********/ #endif -#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_FileListComponent.h *********/ -#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ -#define __JUCE_FILELISTCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_TextPropertyComponent.h *********/ +#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ +#define __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ /** - A component that displays the files in a directory as a listbox. - - This implements the DirectoryContentsDisplayComponent base class so that - it can be used in a FileBrowserComponent. - - To attach a listener to it, use its DirectoryContentsDisplayComponent base - class and the FileBrowserListener class. + A PropertyComponent that shows its value as editable text. - @see DirectoryContentsList, FileTreeComponent + @see PropertyComponent */ -class JUCE_API FileListComponent : public ListBox, - public DirectoryContentsDisplayComponent, - private ListBoxModel, - private ChangeListener +class JUCE_API TextPropertyComponent : public PropertyComponent { public: - /** Creates a listbox to show the contents of a specified directory. + /** Creates a text property component. + + The maxNumChars is used to set the length of string allowable, and isMultiLine + sets whether the text editor allows carriage returns. + + @see TextEditor */ - FileListComponent (DirectoryContentsList& listToShow); + TextPropertyComponent (const String& propertyName, + const int maxNumChars, + const bool isMultiLine); /** Destructor. */ - ~FileListComponent(); + ~TextPropertyComponent(); - /** Returns the number of files the user has got selected. - @see getSelectedFile - */ - int getNumSelectedFiles() const; + /** Called when the user edits the text. - /** Returns one of the files that the user has currently selected. - The index should be in the range 0 to (getNumSelectedFiles() - 1). - @see getNumSelectedFiles + Your subclass must use this callback to change the value of whatever item + this property component represents. */ - const File getSelectedFile (int index = 0) const; + virtual void setText (const String& newText) = 0; - /** Scrolls to the top of the list. */ - void scrollToTop(); + /** Returns the text that should be shown in the text editor. + */ + virtual const String getText() const = 0; /** @internal */ - void changeListenerCallback (void*); - /** @internal */ - int getNumRows(); - /** @internal */ - void paintListBoxItem (int, Graphics&, int, int, bool); - /** @internal */ - Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate); - /** @internal */ - void selectedRowsChanged (int lastRowSelected); - /** @internal */ - void deleteKeyPressed (int currentSelectedRow); + void refresh(); /** @internal */ - void returnKeyPressed (int currentSelectedRow); + void textWasEdited(); juce_UseDebuggingNewOperator private: - FileListComponent (const FileListComponent&); - const FileListComponent& operator= (const FileListComponent&); - - File lastDirectory; + Label* textEditor; }; -#endif // __JUCE_FILELISTCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FileListComponent.h *********/ +#endif // __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_TextPropertyComponent.h *********/ #endif -#ifndef __JUCE_FILEFILTER_JUCEHEADER__ +#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ -#endif -#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_ActiveXControlComponent.h *********/ +#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ +#define __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_FileTreeComponent.h *********/ -#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ -#define __JUCE_FILETREECOMPONENT_JUCEHEADER__ +#if JUCE_WINDOWS || DOXYGEN /** - A component that displays the files in a directory as a treeview. - - This implements the DirectoryContentsDisplayComponent base class so that - it can be used in a FileBrowserComponent. + A Windows-specific class that can create and embed an ActiveX control inside + itself. - To attach a listener to it, use its DirectoryContentsDisplayComponent base - class and the FileBrowserListener class. + To use it, create one of these, put it in place and make sure it's visible in a + window, then use createControl() to instantiate an ActiveX control. The control + will then be moved and resized to follow the movements of this component. - @see DirectoryContentsList, FileListComponent + Of course, since the control is a heavyweight window, it'll obliterate any + juce components that may overlap this component, but that's life. */ -class JUCE_API FileTreeComponent : public TreeView, - public DirectoryContentsDisplayComponent +class JUCE_API ActiveXControlComponent : public Component { public: - /** Creates a listbox to show the contents of a specified directory. - */ - FileTreeComponent (DirectoryContentsList& listToShow); + /** Create an initially-empty container. */ + ActiveXControlComponent(); /** Destructor. */ - ~FileTreeComponent(); + ~ActiveXControlComponent(); - /** Returns the number of files the user has got selected. - @see getSelectedFile + /** Tries to create an ActiveX control and embed it in this peer. + + The peer controlIID is a pointer to an IID structure - it's treated + as a void* because when including the Juce headers, you might not always + have included windows.h first, in which case IID wouldn't be defined. + + e.g. @code + const IID myIID = __uuidof (QTControl); + myControlComp->createControl (&myIID); + @endcode */ - int getNumSelectedFiles() const { return TreeView::getNumSelectedItems(); } + bool createControl (const void* controlIID); - /** Returns one of the files that the user has currently selected. - The index should be in the range 0 to (getNumSelectedFiles() - 1). - @see getNumSelectedFiles + /** Deletes the ActiveX control, if one has been created. */ - const File getSelectedFile (int index = 0) const; + void deleteControl(); - /** Scrolls the list to the top. */ - void scrollToTop(); + /** Returns true if a control is currently in use. */ + bool isControlOpen() const throw() { return control != 0; } - /** Setting a name for this allows tree items to be dragged. + /** Does a QueryInterface call on the embedded control object. - The string that you pass in here will be returned by the getDragSourceDescription() - of the items in the tree. For more info, see TreeViewItem::getDragSourceDescription(). + This allows you to cast the control to whatever type of COM object you need. + + The iid parameter is a pointer to an IID structure - it's treated + as a void* because when including the Juce headers, you might not always + have included windows.h first, in which case IID wouldn't be defined, but + you should just pass a pointer to an IID. + + e.g. @code + const IID iid = __uuidof (IOleWindow); + + IOleWindow* oleWindow = (IOleWindow*) myControlComp->queryInterface (&iid); + + if (oleWindow != 0) + { + HWND hwnd; + oleWindow->GetWindow (&hwnd); + + ... + + oleWindow->Release(); + } + @endcode */ - void setDragAndDropDescription (const String& description) throw(); + void* queryInterface (const void* iid) const; - /** Returns the last value that was set by setDragAndDropDescription(). + /** Set this to false to stop mouse events being allowed through to the control. */ - const String& getDragAndDropDescription() const throw() { return dragAndDropDescription; } + void setMouseEventsAllowed (const bool eventsCanReachControl); + + /** Returns true if mouse events are allowed to get through to the control. + */ + bool areMouseEventsAllowed() const throw() { return mouseEventsAllowed; } + + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void* originalWndProc; juce_UseDebuggingNewOperator private: - String dragAndDropDescription; + friend class ActiveXControlData; + void* control; + bool mouseEventsAllowed; - FileTreeComponent (const FileTreeComponent&); - const FileTreeComponent& operator= (const FileTreeComponent&); -}; + ActiveXControlComponent (const ActiveXControlComponent&); + const ActiveXControlComponent& operator= (const ActiveXControlComponent&); -#endif // __JUCE_FILETREECOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FileTreeComponent.h *********/ + void setControlBounds (const Rectangle& bounds) const; + void setControlVisible (const bool b) const; +}; #endif -#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ -/********* Start of inlined file: juce_FileChooserDialogBox.h *********/ -#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ -#define __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ +#endif // __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_ActiveXControlComponent.h *********/ -/********* Start of inlined file: juce_FileBrowserComponent.h *********/ -#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ -#define __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_FilePreviewComponent.h *********/ -#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ -#define __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_AudioDeviceSelectorComponent.h *********/ +#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ +#define __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ + +class MidiInputSelectorComponentListBox; /** - Base class for components that live inside a file chooser dialog box and - show previews of the files that get selected. + A component containing controls to let the user change the audio settings of + an AudioDeviceManager object. - One of these allows special extra information to be displayed for files - in a dialog box as the user selects them. Each time the current file or - directory is changed, the selectedFileChanged() method will be called - to allow it to update itself appropriately. + Very easy to use - just create one of these and show it to the user. - @see FileChooser, ImagePreviewComponent + @see AudioDeviceManager */ -class JUCE_API FilePreviewComponent : public Component +class JUCE_API AudioDeviceSelectorComponent : public Component, + public ComboBoxListener, + public ButtonListener, + public ChangeListener { public: - /** Creates a FilePreviewComponent. */ - FilePreviewComponent(); - - /** Destructor. */ - ~FilePreviewComponent(); + /** Creates the component. - /** Called to indicate that the user's currently selected file has changed. + If your app needs only output channels, you might ask for a maximum of 0 input + channels, and the component won't display any options for choosing the input + channels. And likewise if you're doing an input-only app. - @param newSelectedFile the newly selected file or directory, which may be - File::nonexistent if none is selected. + @param deviceManager the device manager that this component should control + @param minAudioInputChannels the minimum number of audio input channels that the application needs + @param maxAudioInputChannels the maximum number of audio input channels that the application needs + @param minAudioOutputChannels the minimum number of audio output channels that the application needs + @param maxAudioOutputChannels the maximum number of audio output channels that the application needs + @param showMidiInputOptions if true, the component will allow the user to select which midi inputs are enabled + @param showMidiOutputSelector if true, the component will let the user choose a default midi output device + @param showChannelsAsStereoPairs if true, channels will be treated as pairs; if false, channels will be + treated as a set of separate mono channels. + @param hideAdvancedOptionsWithButton if true, only the minimum amount of UI components + are shown, with an "advanced" button that shows the rest of them */ - virtual void selectedFileChanged (const File& newSelectedFile) = 0; + AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager, + const int minAudioInputChannels, + const int maxAudioInputChannels, + const int minAudioOutputChannels, + const int maxAudioOutputChannels, + const bool showMidiInputOptions, + const bool showMidiOutputSelector, + const bool showChannelsAsStereoPairs, + const bool hideAdvancedOptionsWithButton); + + /** Destructor */ + ~AudioDeviceSelectorComponent(); + + /** @internal */ + void resized(); + /** @internal */ + void comboBoxChanged (ComboBox*); + /** @internal */ + void buttonClicked (Button*); + /** @internal */ + void changeListenerCallback (void*); + /** @internal */ + void childBoundsChanged (Component*); juce_UseDebuggingNewOperator private: - FilePreviewComponent (const FilePreviewComponent&); - const FilePreviewComponent& operator= (const FilePreviewComponent&); + AudioDeviceManager& deviceManager; + ComboBox* deviceTypeDropDown; + Label* deviceTypeDropDownLabel; + Component* audioDeviceSettingsComp; + String audioDeviceSettingsCompType; + const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels; + const bool showChannelsAsStereoPairs; + const bool hideAdvancedOptionsWithButton; + + MidiInputSelectorComponentListBox* midiInputsList; + Label* midiInputsLabel; + ComboBox* midiOutputSelector; + Label* midiOutputLabel; + + AudioDeviceSelectorComponent (const AudioDeviceSelectorComponent&); + const AudioDeviceSelectorComponent& operator= (const AudioDeviceSelectorComponent&); }; -#endif // __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FilePreviewComponent.h *********/ +#endif // __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_AudioDeviceSelectorComponent.h *********/ + +#endif +#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_BubbleComponent.h *********/ +#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ +#define __JUCE_BUBBLECOMPONENT_JUCEHEADER__ /** - A component for browsing and selecting a file or directory to open or save. + A component for showing a message or other graphics inside a speech-bubble-shaped + outline, pointing at a location on the screen. - This contains a FileListComponent and adds various boxes and controls for - navigating and selecting a file. It can work in different modes so that it can - be used for loading or saving a file, or for choosing a directory. + This is a base class that just draws and positions the bubble shape, but leaves + the drawing of any content up to a subclass. See BubbleMessageComponent for a subclass + that draws a text message. - @see FileChooserDialogBox, FileChooser, FileListComponent + To use it, create your subclass, then either add it to a parent component or + put it on the desktop with addToDesktop (0), use setPosition() to + resize and position it, then make it visible. + + @see BubbleMessageComponent */ -class JUCE_API FileBrowserComponent : public Component, - public ChangeBroadcaster, - private FileBrowserListener, - private TextEditorListener, - private ButtonListener, - private ComboBoxListener, - private FileFilter +class JUCE_API BubbleComponent : public Component { +protected: + + /** Creates a BubbleComponent. + + Your subclass will need to implement the getContentSize() and paintContent() + methods to draw the bubble's contents. + */ + BubbleComponent(); + public: + /** Destructor. */ + ~BubbleComponent(); - /** Various options for the browser. + /** A list of permitted placements for the bubble, relative to the co-ordinates + at which it should be pointing. - A combination of these is passed into the FileBrowserComponent constructor. + @see setAllowedPlacement */ - enum FileChooserFlags + enum BubblePlacement { - openMode = 1, /**< specifies that the component should allow the user to - choose an existing file with the intention of opening it. */ - saveMode = 2, /**< specifies that the component should allow the user to specify - the name of a file that will be used to save something. */ - canSelectFiles = 4, /**< specifies that the user can select files (can be used in - conjunction with canSelectDirectories). */ - canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in - conjuction with canSelectFiles). */ - canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ - useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ - filenameBoxIsReadOnly = 64 /**< specifies that the user can't type directly into the filename box. */ + above = 1, + below = 2, + left = 4, + right = 8 }; - /** Creates a FileBrowserComponent. - - @param flags A combination of flags from the FileChooserFlags enumeration, - used to specify the component's behaviour. The flags must contain - either openMode or saveMode, and canSelectFiles and/or - canSelectDirectories. - @param initialFileOrDirectory The file or directory that should be selected when - the component begins. If this is File::nonexistent, - a default directory will be chosen. - @param fileFilter an optional filter to use to determine which files - are shown. If this is 0 then all files are displayed. Note - that a pointer is kept internally to this object, so - make sure that it is not deleted before the browser object - is deleted. - @param previewComp an optional preview component that will be used to - show previews of files that the user selects - */ - FileBrowserComponent (int flags, - const File& initialFileOrDirectory, - const FileFilter* fileFilter, - FilePreviewComponent* previewComp); + /** Tells the bubble which positions it's allowed to put itself in, relative to the + point at which it's pointing. - /** Destructor. */ - ~FileBrowserComponent(); + By default when setPosition() is called, the bubble will place itself either + above, below, left, or right of the target area. You can pass in a bitwise-'or' of + the values in BubblePlacement to restrict this choice. - /** Returns the number of files that the user has got selected. - If multiple select isn't active, this will only be 0 or 1. To get the complete - list of files they've chosen, pass an index to getCurrentFile(). - */ - int getNumSelectedFiles() const throw(); + E.g. if you only want your bubble to appear above or below the target area, + use setAllowedPlacement (above | below); - /** Returns one of the files that the user has chosen. - If the box has multi-select enabled, the index lets you specify which of the files - to get - see getNumSelectedFiles() to find out how many files were chosen. - @see getHighlightedFile + @see BubblePlacement */ - const File getSelectedFile (int index) const throw(); + void setAllowedPlacement (const int newPlacement); - /** Returns true if the currently selected file(s) are usable. + /** Moves and resizes the bubble to point at a given component. - This can be used to decide whether the user can press "ok" for the - current file. What it does depends on the mode, so for example in an "open" - mode, this only returns true if a file has been selected and if it exists. - In a "save" mode, a non-existent file would also be valid. - */ - bool currentFileIsValid() const; + This will resize the bubble to fit its content, then find a position for it + so that it's next to, but doesn't overlap the given component. - /** This returns the last item in the view that the user has highlighted. - This may be different from getCurrentFile(), which returns the value - that is shown in the filename box, and if there are multiple selections, - this will only return one of them. - @see getCurrentFile + It'll put itself either above, below, or to the side of the component depending + on where there's the most space, honouring any restrictions that were set + with setAllowedPlacement(). */ - const File getHighlightedFile() const throw(); - - /** Returns the directory whose contents are currently being shown in the listbox. */ - const File getRoot() const; + void setPosition (Component* componentToPointTo); - /** Changes the directory that's being shown in the listbox. */ - void setRoot (const File& newRootDirectory); + /** Moves and resizes the bubble to point at a given point. - /** Equivalent to pressing the "up" button to browse the parent directory. */ - void goUp(); + This will resize the bubble to fit its content, then position it + so that the tip of the bubble points to the given co-ordinate. The co-ordinates + are relative to either the bubble component's parent component if it has one, or + they are screen co-ordinates if not. - /** Refreshes the directory that's currently being listed. */ - void refresh(); + It'll put itself either above, below, or to the side of this point, depending + on where there's the most space, honouring any restrictions that were set + with setAllowedPlacement(). + */ + void setPosition (const int arrowTipX, + const int arrowTipY); - /** Returns a verb to describe what should happen when the file is accepted. + /** Moves and resizes the bubble to point at a given rectangle. - E.g. if browsing in "load file" mode, this will be "Open", if in "save file" - mode, it'll be "Save", etc. - */ - virtual const String getActionVerb() const; + This will resize the bubble to fit its content, then find a position for it + so that it's next to, but doesn't overlap the given rectangle. The rectangle's + co-ordinates are relative to either the bubble component's parent component + if it has one, or they are screen co-ordinates if not. - /** Returns true if the saveMode flag was set when this component was created. + It'll put itself either above, below, or to the side of the component depending + on where there's the most space, honouring any restrictions that were set + with setAllowedPlacement(). */ - bool isSaveMode() const throw(); + void setPosition (const Rectangle& rectangleToPointTo); - /** Adds a listener to be told when the user selects and clicks on files. +protected: - @see removeListener + /** Subclasses should override this to return the size of the content they + want to draw inside the bubble. */ - void addListener (FileBrowserListener* const listener) throw(); + virtual void getContentSize (int& width, int& height) = 0; - /** Removes a listener. + /** Subclasses should override this to draw their bubble's contents. - @see addListener + The graphics object's clip region and the dimensions passed in here are + set up to paint just the rectangle inside the bubble. */ - void removeListener (FileBrowserListener* const listener) throw(); + virtual void paintContent (Graphics& g, int width, int height) = 0; - /** @internal */ - void resized(); - /** @internal */ - void buttonClicked (Button* b); - /** @internal */ - void comboBoxChanged (ComboBox*); - /** @internal */ - void textEditorTextChanged (TextEditor& editor); - /** @internal */ - void textEditorReturnKeyPressed (TextEditor& editor); - /** @internal */ - void textEditorEscapeKeyPressed (TextEditor& editor); - /** @internal */ - void textEditorFocusLost (TextEditor& editor); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void selectionChanged(); - /** @internal */ - void fileClicked (const File& f, const MouseEvent& e); - /** @internal */ - void fileDoubleClicked (const File& f); - /** @internal */ - bool isFileSuitable (const File& file) const; - /** @internal */ - bool isDirectorySuitable (const File&) const; +public: /** @internal */ - FilePreviewComponent* getPreviewComponent() const throw(); + void paint (Graphics& g); juce_UseDebuggingNewOperator -protected: - virtual const BitArray getRoots (StringArray& rootNames, StringArray& rootPaths); - -private: - - DirectoryContentsList* fileList; - const FileFilter* fileFilter; - - int flags; - File currentRoot; - OwnedArray chosenFiles; - SortedSet listeners; - - DirectoryContentsDisplayComponent* fileListComponent; - FilePreviewComponent* previewComp; - ComboBox* currentPathBox; - TextEditor* filenameBox; - Button* goUpButton; - - TimeSliceThread thread; - - void sendListenerChangeMessage(); - bool isFileOrDirSuitable (const File& f) const; - - FileBrowserComponent (const FileBrowserComponent&); - const FileBrowserComponent& operator= (const FileBrowserComponent&); -}; - -#endif // __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FileBrowserComponent.h *********/ - -/** - A file open/save dialog box. +private: + Rectangle content; + int side, allowablePlacements; + float arrowTipX, arrowTipY; + DropShadowEffect shadow; - This is a Juce-based file dialog box; to use a native file chooser, see the - FileChooser class. + BubbleComponent (const BubbleComponent&); + const BubbleComponent& operator= (const BubbleComponent&); +}; - To use one of these, create it and call its show() method. e.g. +#endif // __JUCE_BUBBLECOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_BubbleComponent.h *********/ - @code - { - WildcardFileFilter wildcardFilter (T("*.foo"), T("Foo files")); +#endif +#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ - FileBrowserComponent browser (FileBrowserComponent::loadFileMode, - File::nonexistent, - &wildcardFilter, - 0); +/********* Start of inlined file: juce_BubbleMessageComponent.h *********/ +#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ +#define __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ - FileChooserDialogBox dialogBox (T("Open some kind of file"), - T("Please choose some kind of file that you want to open..."), - browser, - getLookAndFeel().alertWindowBackground); +/** + A speech-bubble component that displays a short message. - if (dialogBox.show()) - { - File selectedFile = browser.getCurrentFile(); - ... - } - } - @endcode + This can be used to show a message with the tail of the speech bubble + pointing to a particular component or location on the screen. - @see FileChooser + @see BubbleComponent */ -class JUCE_API FileChooserDialogBox : public ResizableWindow, - public ButtonListener, - public FileBrowserListener +class JUCE_API BubbleMessageComponent : public BubbleComponent, + private Timer { public: - /** Creates a file chooser box. - - @param title the main title to show at the top of the box - @param instructions an optional longer piece of text to show below the title in - a smaller font, describing in more detail what's required. - @param browserComponent a FileBrowserComponent that will be shown inside this dialog - box. Make sure you delete this after (but not before!) the - dialog box has been deleted. - @param warnAboutOverwritingExistingFiles if true, then the user will be asked to confirm - if they try to select a file that already exists. (This - flag is only used when saving files) - @param backgroundColour the background colour for the top level window + /** Creates a bubble component. - @see FileBrowserComponent, FilePreviewComponent + After creating one a BubbleComponent, do the following: + - add it to an appropriate parent component, or put it on the + desktop with Component::addToDesktop (0). + - use the showAt() method to show a message. + - it will make itself invisible after it times-out (and can optionally + also delete itself), or you can reuse it somewhere else by calling + showAt() again. */ - FileChooserDialogBox (const String& title, - const String& instructions, - FileBrowserComponent& browserComponent, - const bool warnAboutOverwritingExistingFiles, - const Colour& backgroundColour); + BubbleMessageComponent (const int fadeOutLengthMs = 150); /** Destructor. */ - ~FileChooserDialogBox(); + ~BubbleMessageComponent(); - /** Displays and runs the dialog box modally. + /** Shows a message bubble at a particular position. - This will show the box with the specified size, returning true if the user - pressed 'ok', or false if they cancelled. + This shows the bubble with its stem pointing to the given location + (co-ordinates being relative to its parent component). - Leave the width or height as 0 to use the default size + For details about exactly how it decides where to position itself, see + BubbleComponent::updatePosition(). + + @param x the x co-ordinate of end of the bubble's tail + @param y the y co-ordinate of end of the bubble's tail + @param message the text to display + @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself + from its parent compnent. If this is 0 or less, it + will stay there until manually removed. + @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a + mouse button is pressed (anywhere on the screen) + @param deleteSelfAfterUse if true, then the component will delete itself after + it becomes invisible */ - bool show (int width = 0,int height = 0); + void showAt (int x, int y, + const String& message, + const int numMillisecondsBeforeRemoving, + const bool removeWhenMouseClicked = true, + const bool deleteSelfAfterUse = false); + + /** Shows a message bubble next to a particular component. + + This shows the bubble with its stem pointing at the given component. + + For details about exactly how it decides where to position itself, see + BubbleComponent::updatePosition(). + + @param component the component that you want to point at + @param message the text to display + @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself + from its parent compnent. If this is 0 or less, it + will stay there until manually removed. + @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a + mouse button is pressed (anywhere on the screen) + @param deleteSelfAfterUse if true, then the component will delete itself after + it becomes invisible + */ + void showAt (Component* const component, + const String& message, + const int numMillisecondsBeforeRemoving, + const bool removeWhenMouseClicked = true, + const bool deleteSelfAfterUse = false); /** @internal */ - void buttonClicked (Button* button); - /** @internal */ - void closeButtonPressed(); - /** @internal */ - void selectionChanged(); + void getContentSize (int& w, int& h); /** @internal */ - void fileClicked (const File& file, const MouseEvent& e); + void paintContent (Graphics& g, int w, int h); /** @internal */ - void fileDoubleClicked (const File& file); + void timerCallback(); juce_UseDebuggingNewOperator private: - class ContentComponent : public Component - { - public: - ContentComponent(); - ~ContentComponent(); - - void paint (Graphics& g); - void resized(); - - String instructions; - GlyphArrangement text; - - FileBrowserComponent* chooserComponent; - FilePreviewComponent* previewComponent; - TextButton* okButton; - TextButton* cancelButton; - }; + int fadeOutLength, mouseClickCounter; + TextLayout textLayout; + int64 expiryTime; + bool deleteAfterUse; - ContentComponent* content; - const bool warnAboutOverwritingExistingFiles; + void init (const int numMillisecondsBeforeRemoving, + const bool removeWhenMouseClicked, + const bool deleteSelfAfterUse); - FileChooserDialogBox (const FileChooserDialogBox&); - const FileChooserDialogBox& operator= (const FileChooserDialogBox&); + BubbleMessageComponent (const BubbleMessageComponent&); + const BubbleMessageComponent& operator= (const BubbleMessageComponent&); }; -#endif // __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ -/********* End of inlined file: juce_FileChooserDialogBox.h *********/ - -#endif -#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ +#endif // __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_BubbleMessageComponent.h *********/ #endif -#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ - -/********* Start of inlined file: juce_FilenameComponent.h *********/ -#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ -#define __JUCE_FILENAMECOMPONENT_JUCEHEADER__ +#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ -class FilenameComponent; +/********* Start of inlined file: juce_ColourSelector.h *********/ +#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ +#define __JUCE_COLOURSELECTOR_JUCEHEADER__ /** - Listens for events happening to a FilenameComponent. + A component that lets the user choose a colour. - Use FilenameComponent::addListener() and FilenameComponent::removeListener() to - register one of these objects for event callbacks when the filename is changed. + This shows RGB sliders and a colourspace that the user can pick colours from. - @see FilenameComponent + This class is also a ChangeBroadcaster, so listeners can register to be told + when the colour changes. */ -class JUCE_API FilenameComponentListener +class JUCE_API ColourSelector : public Component, + public ChangeBroadcaster, + protected SliderListener { public: - /** Destructor. */ - virtual ~FilenameComponentListener() {} - - /** This method is called after the FilenameComponent's file has been changed. */ - virtual void filenameComponentChanged (FilenameComponent* fileComponentThatHasChanged) = 0; -}; -/** - Shows a filename as an editable text box, with a 'browse' button and a - drop-down list for recently selected files. + /** Options for the type of selector to show. These are passed into the constructor. */ + enum ColourSelectorOptions + { + showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */ - A handy component for dialogue boxes where you want the user to be able to - select a file or directory. + showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */ + showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */ + showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */ + }; - Attach an FilenameComponentListener using the addListener() method, and it will - get called each time the user changes the filename, either by browsing for a file - and clicking 'ok', or by typing a new filename into the box and pressing return. + /** Creates a ColourSelector object. - @see FileChooser, ComboBox -*/ -class JUCE_API FilenameComponent : public Component, - public SettableTooltipClient, - public FileDragAndDropTarget, - private AsyncUpdater, - private ButtonListener, - private ComboBoxListener -{ -public: + The flags are a combination of values from the ColourSelectorOptions enum, specifying + which of the selector's features should be visible. - /** Creates a FilenameComponent. + The edgeGap value specifies the amount of space to leave around the edge. - @param name the name for this component. - @param currentFile the file to initially show in the box - @param canEditFilename if true, the user can manually edit the filename; if false, - they can only change it by browsing for a new file - @param isDirectory if true, the file will be treated as a directory, and - an appropriate directory browser used - @param isForSaving if true, the file browser will allow non-existent files to - be picked, as the file is assumed to be used for saving rather - than loading - @param fileBrowserWildcard a wildcard pattern to use in the file browser - e.g. "*.txt;*.foo". - If an empty string is passed in, then the pattern is assumed to be "*" - @param enforcedSuffix if this is non-empty, it is treated as a suffix that will be added - to any filenames that are entered or chosen - @param textWhenNothingSelected the message to display in the box before any filename is entered. (This - will only appear if the initial file isn't valid) + gapAroundColourSpaceComponent indicates how much of a gap to put around the + colourspace and hue selector components. */ - FilenameComponent (const String& name, - const File& currentFile, - const bool canEditFilename, - const bool isDirectory, - const bool isForSaving, - const String& fileBrowserWildcard, - const String& enforcedSuffix, - const String& textWhenNothingSelected); + ColourSelector (const int sectionsToShow = (showAlphaChannel | showColourAtTop | showSliders | showColourspace), + const int edgeGap = 4, + const int gapAroundColourSpaceComponent = 7); /** Destructor. */ - ~FilenameComponent(); - - /** Returns the currently displayed filename. */ - const File getCurrentFile() const; + ~ColourSelector(); - /** Changes the current filename. + /** Returns the colour that the user has currently selected. - If addToRecentlyUsedList is true, the filename will also be added to the - drop-down list of recent files. + The ColourSelector class is also a ChangeBroadcaster, so listeners can + register to be told when the colour changes. - If sendChangeNotification is false, then the listeners won't be told of the - change. + @see setCurrentColour */ - void setCurrentFile (File newFile, - const bool addToRecentlyUsedList, - const bool sendChangeNotification = true); + const Colour getCurrentColour() const; - /** Changes whether the use can type into the filename box. + /** Changes the colour that is currently being shown. */ - void setFilenameIsEditable (const bool shouldBeEditable); + void setCurrentColour (const Colour& newColour); - /** Sets a file or directory to be the default starting point for the browser to show. + /** Tells the selector how many preset colour swatches you want to have on the component. - This is only used if the current file hasn't been set. + To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and + setSwatchColour(), to return the number of colours you want, and to set and retrieve + their values. */ - void setDefaultBrowseTarget (const File& newDefaultDirectory) throw(); + virtual int getNumSwatches() const; - /** Returns all the entries on the recent files list. + /** Called by the selector to find out the colour of one of the swatches. - This can be used in conjunction with setRecentlyUsedFilenames() for saving the - state of this list. + Your subclass should return the colour of the swatch with the given index. - @see setRecentlyUsedFilenames + To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and + setSwatchColour(), to return the number of colours you want, and to set and retrieve + their values. */ - const StringArray getRecentlyUsedFilenames() const; + virtual const Colour getSwatchColour (const int index) const; - /** Sets all the entries on the recent files list. + /** Called by the selector when the user puts a new colour into one of the swatches. - This can be used in conjunction with getRecentlyUsedFilenames() for saving the - state of this list. + Your subclass should change the colour of the swatch with the given index. - @see getRecentlyUsedFilenames, addRecentlyUsedFile + To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and + setSwatchColour(), to return the number of colours you want, and to set and retrieve + their values. */ - void setRecentlyUsedFilenames (const StringArray& filenames); + virtual void setSwatchColour (const int index, const Colour& newColour) const; - /** Adds an entry to the recently-used files dropdown list. + /** A set of colour IDs to use to change the colour of various aspects of the keyboard. - If the file is already in the list, it will be moved to the top. A limit - is also placed on the number of items that are kept in the list. + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - @see getRecentlyUsedFilenames, setRecentlyUsedFilenames, setMaxNumberOfRecentFiles + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ - void addRecentlyUsedFile (const File& file); + enum ColourIds + { + backgroundColourId = 0x1007000, /**< the colour used to fill the component's background. */ + labelTextColourId = 0x1007001 /**< the colour used for the labels next to the sliders. */ + }; - /** Changes the limit for the number of files that will be stored in the recent-file list. - */ - void setMaxNumberOfRecentFiles (const int newMaximum); + juce_UseDebuggingNewOperator - /** Changes the text shown on the 'browse' button. +private: + friend class ColourSpaceView; + friend class HueSelectorComp; + Colour colour; + float h, s, v; + Slider* sliders[4]; + Component* colourSpace; + Component* hueSelector; + VoidArray swatchComponents; + const int flags; + int topSpace, edgeGap; - By default this button just says "..." but you can change it. The button itself - can be changed using the look-and-feel classes, so it might not actually have any - text on it. + void setHue (float newH); + void setSV (float newS, float newV); + void updateHSV(); + void update(); + void sliderValueChanged (Slider*); + void paint (Graphics& g); + void resized(); + + ColourSelector (const ColourSelector&); + const ColourSelector& operator= (const ColourSelector&); + + // this constructor is here temporarily to prevent old code compiling, because the parameters + // have changed - if you get an error here, update your code to use the new constructor instead.. + // (xxx - note to self: remember to remove this at some point in the future) + ColourSelector (const bool); +}; + +#endif // __JUCE_COLOURSELECTOR_JUCEHEADER__ +/********* End of inlined file: juce_ColourSelector.h *********/ + +#endif +#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ + +#endif +#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ + +/********* Start of inlined file: juce_MagnifierComponent.h *********/ +#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ +#define __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ + +/** + A component that contains another component, and can magnify or shrink it. + + This component will continually update its size so that it fits the zoomed + version of the content component that you put inside it, so don't try to + change the size of this component directly - instead change that of the + content component. + + To make it all work, the magnifier uses extremely cunning ComponentPeer tricks + to remap mouse events correctly. This means that the content component won't + appear to be a direct child of this component, and instead will think its + on the desktop. +*/ +class JUCE_API MagnifierComponent : public Component +{ +public: + + /** Creates a MagnifierComponent. + + This component will continually update its size so that it fits the zoomed + version of the content component that you put inside it, so don't try to + change the size of this component directly - instead change that of the + content component. + + @param contentComponent the component to add as the magnified one + @param deleteContentCompWhenNoLongerNeeded if true, the content component will + be deleted when this component is deleted. If false, + it's the caller's responsibility to delete it later. */ - void setBrowseButtonText (const String& browseButtonText); + MagnifierComponent (Component* const contentComponent, + const bool deleteContentCompWhenNoLongerNeeded); - /** Adds a listener that will be called when the selected file is changed. */ - void addListener (FilenameComponentListener* const listener) throw(); + /** Destructor. */ + ~MagnifierComponent(); - /** Removes a previously-registered listener. */ - void removeListener (FilenameComponentListener* const listener) throw(); + /** Returns the current content component. */ + Component* getContentComponent() const throw() { return content; } - /** Gives the component a tooltip. */ - void setTooltip (const String& newTooltip); + /** Changes the zoom level. - /** @internal */ - void paintOverChildren (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - bool isInterestedInFileDrag (const StringArray& files); - /** @internal */ - void filesDropped (const StringArray& files, int, int); - /** @internal */ - void fileDragEnter (const StringArray& files, int, int); - /** @internal */ - void fileDragExit (const StringArray& files); + The scale factor must be greater than zero. Values less than 1 will shrink the + image; values greater than 1 will multiply its size by this amount. + + When this is called, this component will change its size to fit the full extent + of the newly zoomed content. + */ + void setScaleFactor (double newScaleFactor); + + /** Returns the current zoom factor. */ + double getScaleFactor() const throw() { return scaleFactor; } + + /** Changes the quality setting used to rescale the graphics. + */ + void setResamplingQuality (Graphics::ResamplingQuality newQuality); juce_UseDebuggingNewOperator + /** @internal */ + void childBoundsChanged (Component*); + private: + Component* content; + Component* holderComp; + double scaleFactor; + ComponentPeer* peer; + bool deleteContent; + Graphics::ResamplingQuality quality; - ComboBox* filenameBox; - String lastFilename; - Button* browseButton; - int maxRecentFiles; - bool isDir, isSaving, isFileDragOver; - String wildcard, enforcedSuffix, browseButtonText; - SortedSet listeners; - File defaultBrowseFile; + void paint (Graphics& g); + void mouseDown (const MouseEvent& e); + void mouseUp (const MouseEvent& e); + void mouseDrag (const MouseEvent& e); + void mouseMove (const MouseEvent& e); + void mouseEnter (const MouseEvent& e); + void mouseExit (const MouseEvent& e); + void mouseWheelMove (const MouseEvent& e, float, float); - void comboBoxChanged (ComboBox*); - void buttonClicked (Button* button); - void handleAsyncUpdate(); + int scaleInt (const int n) const throw(); - FilenameComponent (const FilenameComponent&); - const FilenameComponent& operator= (const FilenameComponent&); + MagnifierComponent (const MagnifierComponent&); + const MagnifierComponent& operator= (const MagnifierComponent&); }; -#endif // __JUCE_FILENAMECOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FilenameComponent.h *********/ +#endif // __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_MagnifierComponent.h *********/ #endif -#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_FileSearchPathListComponent.h *********/ -#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ -#define __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_MidiKeyboardComponent.h *********/ +#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ +#define __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ /** - Shows a set of file paths in a list, allowing them to be added, removed or - re-ordered. + A component that displays a piano keyboard, whose notes can be clicked on. - @see FileSearchPath -*/ -class JUCE_API FileSearchPathListComponent : public Component, - public SettableTooltipClient, - public FileDragAndDropTarget, - private ButtonListener, - private ListBoxModel + This component will mimic a physical midi keyboard, showing the current state of + a MidiKeyboardState object. When the on-screen keys are clicked on, it will play these + notes by calling the noteOn() and noteOff() methods of its MidiKeyboardState object. + + Another feature is that the computer keyboard can also be used to play notes. By + default it maps the top two rows of a standard querty keyboard to the notes, but + these can be remapped if needed. It will only respond to keypresses when it has + the keyboard focus, so to disable this feature you can call setWantsKeyboardFocus (false). + + The component is also a ChangeBroadcaster, so if you want to be informed when the + keyboard is scrolled, you can register a ChangeListener for callbacks. + + @see MidiKeyboardState +*/ +class JUCE_API MidiKeyboardComponent : public Component, + public MidiKeyboardStateListener, + public ChangeBroadcaster, + private Timer, + private AsyncUpdater { public: - /** Creates an empty FileSearchPathListComponent. + /** The direction of the keyboard. + @see setOrientation */ - FileSearchPathListComponent(); + enum Orientation + { + horizontalKeyboard, + verticalKeyboardFacingLeft, + verticalKeyboardFacingRight, + }; - /** Destructor. */ - ~FileSearchPathListComponent(); + /** Creates a MidiKeyboardComponent. - /** Returns the path as it is currently shown. */ - const FileSearchPath& getPath() const throw() { return path; } + @param state the midi keyboard model that this component will represent + @param orientation whether the keyboard is horizonal or vertical + */ + MidiKeyboardComponent (MidiKeyboardState& state, + const Orientation orientation); - /** Changes the current path. */ - void setPath (const FileSearchPath& newPath); + /** Destructor. */ + ~MidiKeyboardComponent(); - /** Sets a file or directory to be the default starting point for the browser to show. + /** Changes the velocity used in midi note-on messages that are triggered by clicking + on the component. - This is only used if the current file hasn't been set. + Values are 0 to 1.0, where 1.0 is the heaviest. + + @see setMidiChannel */ - void setDefaultBrowseTarget (const File& newDefaultDirectory) throw(); + void setVelocity (const float velocity, const bool useMousePositionForVelocity); - /** A set of colour IDs to use to change the colour of various aspects of the label. + /** Changes the midi channel number that will be used for events triggered by clicking + on the component. - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + The channel must be between 1 and 16 (inclusive). This is the channel that will be + passed on to the MidiKeyboardState::noteOn() method when the user clicks the component. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + Although this is the channel used for outgoing events, the component can display + incoming events from more than one channel - see setMidiChannelsToDisplay() + + @see setVelocity */ - enum ColourIds - { - backgroundColourId = 0x1004100, /**< The background colour to fill the component with. - Make this transparent if you don't want the background to be filled. */ - }; + void setMidiChannel (const int midiChannelNumber); - /** @internal */ - int getNumRows(); - /** @internal */ - void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected); - /** @internal */ - void deleteKeyPressed (int lastRowSelected); - /** @internal */ - void returnKeyPressed (int lastRowSelected); - /** @internal */ - void listBoxItemDoubleClicked (int row, const MouseEvent&); - /** @internal */ - void selectedRowsChanged (int lastRowSelected); - /** @internal */ - void resized(); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - bool isInterestedInFileDrag (const StringArray& files); - /** @internal */ - void filesDropped (const StringArray& files, int, int); - /** @internal */ - void buttonClicked (Button* button); + /** Returns the midi channel that the keyboard is using for midi messages. - juce_UseDebuggingNewOperator + @see setMidiChannel + */ + int getMidiChannel() const throw() { return midiChannel; } -private: + /** Sets a mask to indicate which incoming midi channels should be represented by + key movements. - FileSearchPath path; - File defaultBrowseTarget; + The mask is a set of bits, where bit 0 = midi channel 1, bit 1 = midi channel 2, etc. - ListBox* listBox; - Button* addButton; - Button* removeButton; - Button* changeButton; - Button* upButton; - Button* downButton; + If the MidiKeyboardState has a key down for any of the channels whose bits are set + in this mask, the on-screen keys will also go down. - void changed() throw(); - void updateButtons() throw(); + By default, this mask is set to 0xffff (all channels displayed). - FileSearchPathListComponent (const FileSearchPathListComponent&); - const FileSearchPathListComponent& operator= (const FileSearchPathListComponent&); -}; + @see setMidiChannel + */ + void setMidiChannelsToDisplay (const int midiChannelMask); -#endif // __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_FileSearchPathListComponent.h *********/ + /** Returns the current set of midi channels represented by the component. -#endif -#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ + This is the value that was set with setMidiChannelsToDisplay(). + */ + int getMidiChannelsToDisplay() const throw() { return midiInChannelMask; } -/********* Start of inlined file: juce_WildcardFileFilter.h *********/ -#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ -#define __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ + /** Changes the width used to draw the white keys. */ + void setKeyWidth (const float widthInPixels); -/** - A type of FileFilter that works by wildcard pattern matching. + /** Returns the width that was set by setKeyWidth(). */ + float getKeyWidth() const throw() { return keyWidth; } - This filter only allows files that match one of the specified patterns, but - allows all directories through. + /** Changes the keyboard's current direction. */ + void setOrientation (const Orientation newOrientation); - @see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent -*/ -class JUCE_API WildcardFileFilter : public FileFilter -{ -public: + /** Returns the keyboard's current direction. */ + const Orientation getOrientation() const throw() { return orientation; } - /** - Creates a wildcard filter for one or more patterns. + /** Sets the range of midi notes that the keyboard will be limited to. - The wildcardPatterns parameter is a comma or semicolon-delimited set of - patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav - or .aiff. + By default the range is 0 to 127 (inclusive), but you can limit this if you + only want a restricted set of the keys to be shown. - The description is a name to show the user in a list of possible patterns, so - for the wav/aiff example, your description might be "audio files". + Note that the values here are inclusive and must be between 0 and 127. */ - WildcardFileFilter (const String& fileWildcardPatterns, - const String& directoryWildcardPatterns, - const String& description); + void setAvailableRange (const int lowestNote, + const int highestNote); - /** Destructor. */ - ~WildcardFileFilter(); + /** Returns the first note in the available range. - /** Returns true if the filename matches one of the patterns specified. */ - bool isFileSuitable (const File& file) const; + @see setAvailableRange + */ + int getRangeStart() const throw() { return rangeStart; } - /** This always returns true. */ - bool isDirectorySuitable (const File& file) const; + /** Returns the last note in the available range. - juce_UseDebuggingNewOperator + @see setAvailableRange + */ + int getRangeEnd() const throw() { return rangeEnd; } -private: - StringArray fileWildcards, directoryWildcards; + /** If the keyboard extends beyond the size of the component, this will scroll + it to show the given key at the start. - static void parse (const String& pattern, StringArray& result) throw(); - static bool match (const File& file, const StringArray& wildcards) throw(); -}; + Whenever the keyboard's position is changed, this will use the ChangeBroadcaster + base class to send a callback to any ChangeListeners that have been registered. + */ + void setLowestVisibleKey (int noteNumber); -#endif // __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ -/********* End of inlined file: juce_WildcardFileFilter.h *********/ + /** Returns the number of the first key shown in the component. -#endif -#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ + @see setLowestVisibleKey + */ + int getLowestVisibleKey() const throw() { return firstKey; } -/********* Start of inlined file: juce_ImagePreviewComponent.h *********/ -#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ -#define __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ + /** Returns the length of the black notes. -/** - A simple preview component that shows thumbnails of image files. + This will be their vertical or horizontal length, depending on the keyboard's orientation. + */ + int getBlackNoteLength() const throw() { return blackNoteLength; } - @see FileChooserDialogBox, FilePreviewComponent -*/ -class JUCE_API ImagePreviewComponent : public FilePreviewComponent, - private Timer -{ -public: + /** If set to true, then scroll buttons will appear at either end of the keyboard + if there are too many notes to fit them all in the component at once. + */ + void setScrollButtonsVisible (const bool canScroll); - /** Creates an ImagePreviewComponent. */ - ImagePreviewComponent(); + /** A set of colour IDs to use to change the colour of various aspects of the keyboard. - /** Destructor. */ - ~ImagePreviewComponent(); + These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() + methods. - /** @internal */ - void selectedFileChanged (const File& newSelectedFile); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void timerCallback(); + @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + */ + enum ColourIds + { + whiteNoteColourId = 0x1005000, + blackNoteColourId = 0x1005001, + keySeparatorLineColourId = 0x1005002, + mouseOverKeyOverlayColourId = 0x1005003, /**< This colour will be overlaid on the normal note colour. */ + keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */ + textLabelColourId = 0x1005005, + upDownButtonBackgroundColourId = 0x1005006, + upDownButtonArrowColourId = 0x1005007 + }; - juce_UseDebuggingNewOperator + /** Returns the position within the component of the left-hand edge of a key. -private: - File fileToLoad; - Image* currentThumbnail; - String currentDetails; + Depending on the keyboard's orientation, this may be a horizontal or vertical + distance, in either direction. + */ + int getKeyStartPosition (const int midiNoteNumber) const; - void getThumbSize (int& w, int& h) const; + /** Deletes all key-mappings. - ImagePreviewComponent (const ImagePreviewComponent&); - const ImagePreviewComponent& operator= (const ImagePreviewComponent&); -}; + @see setKeyPressForNote + */ + void clearKeyMappings(); -#endif // __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ImagePreviewComponent.h *********/ + /** Maps a key-press to a given note. -#endif -#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ + @param key the key that should trigger the note + @param midiNoteOffsetFromC how many semitones above C the triggered note should + be. The actual midi note that gets played will be + this value + (12 * the current base octave). To change + the base octave, see setKeyPressBaseOctave() + */ + void setKeyPressForNote (const KeyPress& key, + const int midiNoteOffsetFromC); -#endif -#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ + /** Removes any key-mappings for a given note. -/********* Start of inlined file: juce_FileChooser.h *********/ -#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ -#define __JUCE_FILECHOOSER_JUCEHEADER__ + For a description of what the note number means, see setKeyPressForNote(). + */ + void removeKeyPressForNote (const int midiNoteOffsetFromC); -/** - Creates a dialog box to choose a file or directory to load or save. + /** Changes the base note above which key-press-triggered notes are played. - To use a FileChooser: - - create one (as a local stack variable is the neatest way) - - call one of its browseFor.. methods - - if this returns true, the user has selected a file, so you can retrieve it - with the getResult() method. + The set of key-mappings that trigger notes can be moved up and down to cover + the entire scale using this method. - e.g. @code - void loadMooseFile() - { - FileChooser myChooser ("Please select the moose you want to load...", - File::getSpecialLocation (File::userHomeDirectory), - "*.moose"); + The value passed in is an octave number between 0 and 10 (inclusive), and + indicates which C is the base note to which the key-mapped notes are + relative. + */ + void setKeyPressBaseOctave (const int newOctaveNumber); - if (myChooser.browseForFileToOpen()) - { - File mooseFile (myChooser.getResult()); + /** This sets the octave number which is shown as the octave number for middle C. - loadMoose (mooseFile); - } - } - @endcode -*/ -class JUCE_API FileChooser -{ -public: + This affects only the default implementation of getWhiteNoteText(), which + passes this octave number to MidiMessage::getMidiNoteName() in order to + get the note text. See MidiMessage::getMidiNoteName() for more info about + the parameter. - /** Creates a FileChooser. + By default this value is set to 3. - After creating one of these, use one of the browseFor... methods to display it. + @see getOctaveForMiddleC + */ + void setOctaveForMiddleC (const int octaveNumForMiddleC) throw(); - @param dialogBoxTitle a text string to display in the dialog box to - tell the user what's going on - @param initialFileOrDirectory the file or directory that should be selected when - the dialog box opens. If this parameter is set to - File::nonexistent, a sensible default directory - will be used instead. - @param filePatternsAllowed a set of file patterns to specify which files can be - selected - each pattern should be separated by a - comma or semi-colon, e.g. "*" or "*.jpg;*.gif". An - empty string means that all files are allowed - @param useOSNativeDialogBox if true, then a native dialog box will be used if - possible; if false, then a Juce-based browser dialog - box will always be used - @see browseForFileToOpen, browseForFileToSave, browseForDirectory + /** This returns the value set by setOctaveForMiddleC(). + @see setOctaveForMiddleC */ - FileChooser (const String& dialogBoxTitle, - const File& initialFileOrDirectory = File::nonexistent, - const String& filePatternsAllowed = String::empty, - const bool useOSNativeDialogBox = true); + int getOctaveForMiddleC() const throw() { return octaveNumForMiddleC; } - /** Destructor. */ - ~FileChooser(); + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void resized(); + /** @internal */ + void mouseMove (const MouseEvent& e); + /** @internal */ + void mouseDrag (const MouseEvent& e); + /** @internal */ + void mouseDown (const MouseEvent& e); + /** @internal */ + void mouseUp (const MouseEvent& e); + /** @internal */ + void mouseEnter (const MouseEvent& e); + /** @internal */ + void mouseExit (const MouseEvent& e); + /** @internal */ + void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); + /** @internal */ + void timerCallback(); + /** @internal */ + bool keyStateChanged (const bool isKeyDown); + /** @internal */ + void focusLost (FocusChangeType cause); + /** @internal */ + void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity); + /** @internal */ + void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber); + /** @internal */ + void handleAsyncUpdate(); + /** @internal */ + void colourChanged(); - /** Shows a dialog box to choose a file to open. + juce_UseDebuggingNewOperator - This will display the dialog box modally, using an "open file" mode, so that - it won't allow non-existent files or directories to be chosen. +protected: + friend class MidiKeyboardUpDownButton; - @param previewComponent an optional component to display inside the dialog - box to show special info about the files that the user - is browsing. The component will not be deleted by this - object, so the caller must take care of it. - @returns true if the user selected a file, in which case, use the getResult() - method to find out what it was. Returns false if they cancelled instead. - @see browseForFileToSave, browseForDirectory - */ - bool browseForFileToOpen (FilePreviewComponent* previewComponent = 0); + /** Draws a white note in the given rectangle. - /** Same as browseForFileToOpen, but allows the user to select multiple files. + isOver indicates whether the mouse is over the key, isDown indicates whether the key is + currently pressed down. - The files that are returned can be obtained by calling getResults(). See - browseForFileToOpen() for more info about the behaviour of this method. + When doing this, be sure to note the keyboard's orientation. */ - bool browseForMultipleFilesToOpen (FilePreviewComponent* previewComponent = 0); + virtual void drawWhiteNote (int midiNoteNumber, + Graphics& g, + int x, int y, int w, int h, + bool isDown, bool isOver, + const Colour& lineColour, + const Colour& textColour); - /** Shows a dialog box to choose a file to save. + /** Draws a black note in the given rectangle. - This will display the dialog box modally, using an "save file" mode, so it - will allow non-existent files to be chosen, but not directories. + isOver indicates whether the mouse is over the key, isDown indicates whether the key is + currently pressed down. - @param warnAboutOverwritingExistingFiles if true, the dialog box will ask - the user if they're sure they want to overwrite a file that already - exists - @returns true if the user chose a file and pressed 'ok', in which case, use - the getResult() method to find out what the file was. Returns false - if they cancelled instead. - @see browseForFileToOpen, browseForDirectory + When doing this, be sure to note the keyboard's orientation. */ - bool browseForFileToSave (const bool warnAboutOverwritingExistingFiles); + virtual void drawBlackNote (int midiNoteNumber, + Graphics& g, + int x, int y, int w, int h, + bool isDown, bool isOver, + const Colour& noteFillColour); - /** Shows a dialog box to choose a directory. + /** Allows text to be drawn on the white notes. - This will display the dialog box modally, using an "open directory" mode, so it - will only allow directories to be returned, not files. + By default this is used to label the C in each octave, but could be used for other things. - @returns true if the user chose a directory and pressed 'ok', in which case, use - the getResult() method to find out what they chose. Returns false - if they cancelled instead. - @see browseForFileToOpen, browseForFileToSave + @see setOctaveForMiddleC */ - bool browseForDirectory(); + virtual const String getWhiteNoteText (const int midiNoteNumber); - /** Same as browseForFileToOpen, but allows the user to select multiple files and directories. + /** Draws the up and down buttons that change the base note. */ + virtual void drawUpDownButton (Graphics& g, int w, int h, + const bool isMouseOver, + const bool isButtonPressed, + const bool movesOctavesUp); - The files that are returned can be obtained by calling getResults(). See - browseForFileToOpen() for more info about the behaviour of this method. - */ - bool browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComponent = 0); + /** Callback when the mouse is clicked on a key. - /** Returns the last file that was chosen by one of the browseFor methods. + You could use this to do things like handle right-clicks on keys, etc. - After calling the appropriate browseFor... method, this method lets you - find out what file or directory they chose. + Return true if you want the click to trigger the note, or false if you + want to handle it yourself and not have the note played. - Note that the file returned is only valid if the browse method returned true (i.e. - if the user pressed 'ok' rather than cancelling). + @see mouseDraggedToKey + */ + virtual bool mouseDownOnKey (int midiNoteNumber, const MouseEvent& e); - If you're using a multiple-file select, then use the getResults() method instead, - to obtain the list of all files chosen. + /** Callback when the mouse is dragged from one key onto another. - @see getResults + @see mouseDownOnKey */ - const File getResult() const; + virtual void mouseDraggedToKey (int midiNoteNumber, const MouseEvent& e); - /** Returns a list of all the files that were chosen during the last call to a - browse method. + /** Calculates the positon of a given midi-note. - This array may be empty if no files were chosen, or can contain multiple entries - if multiple files were chosen. + This can be overridden to create layouts with custom key-widths. - @see getResult + @param midiNoteNumber the note to find + @param keyWidth the desired width in pixels of one key - see setKeyWidth() + @param x the x position of the left-hand edge of the key (this method + always works in terms of a horizontal keyboard) + @param w the width of the key */ - const OwnedArray & getResults() const; - - juce_UseDebuggingNewOperator + virtual void getKeyPosition (int midiNoteNumber, float keyWidth, + int& x, int& w) const; private: - String title, filters; - File startingFile; - OwnedArray results; - bool useNativeDialogBox; - bool showDialog (const bool selectsDirectories, - const bool selectsFiles, - const bool isSave, - const bool warnAboutOverwritingExistingFiles, - const bool selectMultipleFiles, - FilePreviewComponent* const previewComponent); + MidiKeyboardState& state; + int xOffset, blackNoteLength; + float keyWidth; + Orientation orientation; + + int midiChannel, midiInChannelMask; + float velocity; + int noteUnderMouse, mouseDownNote; + BitArray keysPressed, keysCurrentlyDrawnDown; + + int rangeStart, rangeEnd, firstKey; + bool canScroll, mouseDragging, useMousePositionForVelocity; + Button* scrollDown; + Button* scrollUp; + + Array keyPresses; + Array keyPressNotes; + int keyMappingOctave; + int octaveNumForMiddleC; + + void getKeyPos (int midiNoteNumber, int& x, int& w) const; + int xyToNote (int x, int y, float& mousePositionVelocity); + int remappedXYToNote (int x, int y, float& mousePositionVelocity) const; + void resetAnyKeysInUse(); + void updateNoteUnderMouse (int x, int y); + void repaintNote (const int midiNoteNumber); - static void showPlatformDialog (OwnedArray& results, - const String& title, - const File& file, - const String& filters, - bool selectsDirectories, - bool selectsFiles, - bool isSave, - bool warnAboutOverwritingExistingFiles, - bool selectMultipleFiles, - FilePreviewComponent* previewComponent); + MidiKeyboardComponent (const MidiKeyboardComponent&); + const MidiKeyboardComponent& operator= (const MidiKeyboardComponent&); }; -#endif // __JUCE_FILECHOOSER_JUCEHEADER__ -/********* End of inlined file: juce_FileChooser.h *********/ +#endif // __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_MidiKeyboardComponent.h *********/ #endif -#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ +#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_AlertWindow.h *********/ -#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ -#define __JUCE_ALERTWINDOW_JUCEHEADER__ +/********* Start of inlined file: juce_NSViewComponent.h *********/ +#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ +#define __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ -/** A window that displays a message and has buttons for the user to react to it. +#if ! DOXYGEN + class NSViewComponentInternal; +#endif - For simple dialog boxes with just a couple of buttons on them, there are - some static methods for running these. +#if JUCE_MAC || DOXYGEN - For more complex dialogs, an AlertWindow can be created, then it can have some - buttons and components added to it, and its runModalLoop() method is then used to - show it. The value returned by runModalLoop() shows which button the - user pressed to dismiss the box. +/** + A Mac-specific class that can create and embed an NSView inside itself. - @see ThreadWithProgressWindow + To use it, create one of these, put it in place and make sure it's visible in a + window, then use setView() to assign an NSView to it. The view will then be + moved and resized to follow the movements of this component. + + Of course, since the view is a native object, it'll obliterate any + juce components that may overlap this component, but that's life. */ -class JUCE_API AlertWindow : public TopLevelWindow, - private ButtonListener +class JUCE_API NSViewComponent : public Component { public: - /** The type of icon to show in the dialog box. */ - enum AlertIconType - { - NoIcon, /**< No icon will be shown on the dialog box. */ - QuestionIcon, /**< A question-mark icon, for dialog boxes that need the - user to answer a question. */ - WarningIcon, /**< An exclamation mark to indicate that the dialog is a - warning about something and shouldn't be ignored. */ - InfoIcon /**< An icon that indicates that the dialog box is just - giving the user some information, which doesn't require - a response from them. */ - }; - - /** Creates an AlertWindow. - - @param title the headline to show at the top of the dialog box - @param message a longer, more descriptive message to show underneath the - headline - @param iconType the type of icon to display - @param associatedComponent if this is non-zero, it specifies the component that the - alert window should be associated with. Depending on the look - and feel, this might be used for positioning of the alert window. - */ - AlertWindow (const String& title, - const String& message, - AlertIconType iconType, - Component* associatedComponent = 0); + /** Create an initially-empty container. */ + NSViewComponent(); - /** Destroys the AlertWindow */ - ~AlertWindow(); + /** Destructor. */ + ~NSViewComponent(); - /** Returns the type of alert icon that was specified when the window - was created. */ - AlertIconType getAlertType() const throw() { return alertIconType; } + /** Assigns an NSView to this peer. - /** Changes the dialog box's message. + The view will be retained and released by this component for as long as + it is needed. To remove the current view, just call setView (0). - This will also resize the window to fit the new message if required. + Note: a void* is used here to avoid including the cocoa headers as + part of the juce.h, but the method expects an NSView*. */ - void setMessage (const String& message); + void setView (void* nsView); - /** Adds a button to the window. + /** Returns the current NSView. - @param name the text to show on the button - @param returnValue the value that should be returned from runModalLoop() - if this is the button that the user presses. - @param shortcutKey1 an optional key that can be pressed to trigger this button - @param shortcutKey2 a second optional key that can be pressed to trigger this button + Note: a void* is returned here to avoid including the cocoa headers as + a requirement of juce.h, so you should just cast the object to an NSView*. */ - void addButton (const String& name, - const int returnValue, - const KeyPress& shortcutKey1 = KeyPress(), - const KeyPress& shortcutKey2 = KeyPress()); + void* getView() const; - /** Returns the number of buttons that the window currently has. */ - int getNumButtons() const; + /** @internal */ + void paint (Graphics& g); - /** Adds a textbox to the window for entering strings. + juce_UseDebuggingNewOperator - @param name an internal name for the text-box. This is the name to pass to - the getTextEditorContents() method to find out what the - user typed-in. - @param initialContents a string to show in the text box when it's first shown - @param onScreenLabel if this is non-empty, it will be displayed next to the - text-box to label it. - @param isPasswordBox if true, the text editor will display asterisks instead of - the actual text - @see getTextEditorContents - */ - void addTextEditor (const String& name, - const String& initialContents, - const String& onScreenLabel = String::empty, - const bool isPasswordBox = false); +private: + friend class NSViewComponentInternal; + NSViewComponentInternal* info; - /** Returns the contents of a named textbox. + NSViewComponent (const NSViewComponent&); + const NSViewComponent& operator= (const NSViewComponent&); +}; - After showing an AlertWindow that contains a text editor, this can be - used to find out what the user has typed into it. +#endif - @param nameOfTextEditor the name of the text box that you're interested in - @see addTextEditor - */ - const String getTextEditorContents (const String& nameOfTextEditor) const; +#endif // __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_NSViewComponent.h *********/ - /** Adds a drop-down list of choices to the box. +#endif +#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ - After the box has been shown, the getComboBoxComponent() method can - be used to find out which item the user picked. +/********* Start of inlined file: juce_OpenGLComponent.h *********/ +#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ +#define __JUCE_OPENGLCOMPONENT_JUCEHEADER__ - @param name the label to use for the drop-down list - @param items the list of items to show in it - @param onScreenLabel if this is non-empty, it will be displayed next to the - combo-box to label it. - @see getComboBoxComponent - */ - void addComboBox (const String& name, - const StringArray& items, - const String& onScreenLabel = String::empty); +// this is used to disable OpenGL, and is defined in juce_Config.h +#if JUCE_OPENGL || DOXYGEN - /** Returns a drop-down list that was added to the AlertWindow. +class OpenGLComponentWatcher; - @param nameOfList the name that was passed into the addComboBox() method - when creating the drop-down - @returns the ComboBox component, or 0 if none was found for the given name. - */ - ComboBox* getComboBoxComponent (const String& nameOfList) const; +/** + Represents the various properties of an OpenGL bitmap format. - /** Adds a block of text. + @see OpenGLComponent::setPixelFormat +*/ +class JUCE_API OpenGLPixelFormat +{ +public: - This is handy for adding a multi-line note next to a textbox or combo-box, - to provide more details about what's going on. + /** Creates an OpenGLPixelFormat. + + The default constructor just initialises the object as a simple 8-bit + RGBA format. */ - void addTextBlock (const String& text); + OpenGLPixelFormat (const int bitsPerRGBComponent = 8, + const int alphaBits = 8, + const int depthBufferBits = 16, + const int stencilBufferBits = 0) throw(); - /** Adds a progress-bar to the window. + int redBits; /**< The number of bits per pixel to use for the red channel. */ + int greenBits; /**< The number of bits per pixel to use for the green channel. */ + int blueBits; /**< The number of bits per pixel to use for the blue channel. */ + int alphaBits; /**< The number of bits per pixel to use for the alpha channel. */ - @param progressValue a variable that will be repeatedly checked while the - dialog box is visible, to see how far the process has - got. The value should be in the range 0 to 1.0 - */ - void addProgressBarComponent (double& progressValue); + int depthBufferBits; /**< The number of bits per pixel to use for a depth buffer. */ + int stencilBufferBits; /**< The number of bits per pixel to use for a stencil buffer. */ - /** Adds a user-defined component to the dialog box. + int accumulationBufferRedBits; /**< The number of bits per pixel to use for an accumulation buffer's red channel. */ + int accumulationBufferGreenBits; /**< The number of bits per pixel to use for an accumulation buffer's green channel. */ + int accumulationBufferBlueBits; /**< The number of bits per pixel to use for an accumulation buffer's blue channel. */ + int accumulationBufferAlphaBits; /**< The number of bits per pixel to use for an accumulation buffer's alpha channel. */ - @param component the component to add - its size should be set up correctly - before it is passed in. The caller is responsible for deleting - the component later on - the AlertWindow won't delete it. - */ - void addCustomComponent (Component* const component); + uint8 fullSceneAntiAliasingNumSamples; /**< The number of samples to use in full-scene anti-aliasing (if available). */ - /** Returns the number of custom components in the dialog box. + /** Returns a list of all the pixel formats that can be used in this system. - @see getCustomComponent, addCustomComponent + A reference component is needed in case there are multiple screens with different + capabilities - in which case, the one that the component is on will be used. */ - int getNumCustomComponents() const; + static void getAvailablePixelFormats (Component* component, + OwnedArray & results); - /** Returns one of the custom components in the dialog box. + bool operator== (const OpenGLPixelFormat&) const throw(); - @param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes - will return 0 - @see getNumCustomComponents, addCustomComponent - */ - Component* getCustomComponent (const int index) const; + juce_UseDebuggingNewOperator +}; - /** Removes one of the custom components in the dialog box. +/** + A base class for types of OpenGL context. - Note that this won't delete it, it just removes the component from the window + An OpenGLComponent will supply its own context for drawing in its window. +*/ +class JUCE_API OpenGLContext +{ +public: - @param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes - will return 0 - @returns the component that was removed (or zero) - @see getNumCustomComponents, addCustomComponent - */ - Component* removeCustomComponent (const int index); + /** Destructor. */ + virtual ~OpenGLContext(); - /** Returns true if the window contains any components other than just buttons.*/ - bool containsAnyExtraComponents() const; + /** Makes this context the currently active one. */ + virtual bool makeActive() const throw() = 0; + /** If this context is currently active, it is disactivated. */ + virtual bool makeInactive() const throw() = 0; + /** Returns true if this context is currently active. */ + virtual bool isActive() const throw() = 0; - // easy-to-use message box functions: + /** Swaps the buffers (if the context can do this). */ + virtual void swapBuffers() = 0; - /** Shows a dialog box that just has a message and a single button to get rid of it. + /** Sets whether the context checks the vertical sync before swapping. - The box is shown modally, and the method returns after the user - has clicked the button (or pressed the escape or return keys). + The value is the number of frames to allow between buffer-swapping. This is + fairly system-dependent, but 0 turns off syncing, 1 makes it swap on frame-boundaries, + and greater numbers indicate that it should swap less often. - @param iconType the type of icon to show - @param title the headline to show at the top of the box - @param message a longer, more descriptive message to show underneath the - headline - @param buttonText the text to show in the button - if this string is empty, the - default string "ok" (or a localised version) will be used. - @param associatedComponent if this is non-zero, it specifies the component that the - alert window should be associated with. Depending on the look - and feel, this might be used for positioning of the alert window. + Returns true if it sets the value successfully. */ - static void JUCE_CALLTYPE showMessageBox (AlertIconType iconType, - const String& title, - const String& message, - const String& buttonText = String::empty, - Component* associatedComponent = 0); + virtual bool setSwapInterval (const int numFramesPerSwap) = 0; - /** Shows a dialog box with two buttons. + /** Returns the current swap-sync interval. + See setSwapInterval() for info about the value returned. + */ + virtual int getSwapInterval() const = 0; - Ideal for ok/cancel or yes/no choices. The return key can also be used - to trigger the first button, and the escape key for the second button. + /** Returns the pixel format being used by this context. */ + virtual const OpenGLPixelFormat getPixelFormat() const = 0; - @param iconType the type of icon to show - @param title the headline to show at the top of the box - @param message a longer, more descriptive message to show underneath the - headline - @param button1Text the text to show in the first button - if this string is - empty, the default string "ok" (or a localised version of it) - will be used. - @param button2Text the text to show in the second button - if this string is - empty, the default string "cancel" (or a localised version of it) - will be used. - @param associatedComponent if this is non-zero, it specifies the component that the - alert window should be associated with. Depending on the look - and feel, this might be used for positioning of the alert window. - @returns true if button 1 was clicked, false if it was button 2 + /** For windowed contexts, this moves the context within the bounds of + its parent window. */ - static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType, - const String& title, - const String& message, - const String& button1Text = String::empty, - const String& button2Text = String::empty, - Component* associatedComponent = 0); - - /** Shows a dialog box with three buttons. + virtual void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) = 0; - Ideal for yes/no/cancel boxes. + /** For windowed contexts, this triggers a repaint of the window. - The escape key can be used to trigger the third button. + (Not relevent on all platforms). + */ + virtual void repaint() = 0; - @param iconType the type of icon to show - @param title the headline to show at the top of the box - @param message a longer, more descriptive message to show underneath the - headline - @param button1Text the text to show in the first button - if an empty string, then - "yes" will be used (or a localised version of it) - @param button2Text the text to show in the first button - if an empty string, then - "no" will be used (or a localised version of it) - @param button3Text the text to show in the first button - if an empty string, then - "cancel" will be used (or a localised version of it) - @param associatedComponent if this is non-zero, it specifies the component that the - alert window should be associated with. Depending on the look - and feel, this might be used for positioning of the alert window. + /** Returns an OS-dependent handle to the raw GL context. - @returns one of the following values: - - 0 if the third button was pressed (normally used for 'cancel') - - 1 if the first button was pressed (normally used for 'yes') - - 2 if the middle button was pressed (normally used for 'no') + On win32, this will be a HGLRC; on the Mac, an AGLContext; on Linux, + a GLXContext. */ - static int JUCE_CALLTYPE showYesNoCancelBox (AlertIconType iconType, - const String& title, - const String& message, - const String& button1Text = String::empty, - const String& button2Text = String::empty, - const String& button3Text = String::empty, - Component* associatedComponent = 0); + virtual void* getRawContext() const throw() = 0; - /** Shows an operating-system native dialog box. + /** This tries to create a context that can be used for drawing into the + area occupied by the specified component. - @param title the title to use at the top - @param bodyText the longer message to show - @param isOkCancel if true, this will show an ok/cancel box, if false, - it'll show a box with just an ok button - @returns true if the ok button was pressed, false if they pressed cancel. + Note that you probably shouldn't use this method directly unless you know what + you're doing - the OpenGLComponent calls this and manages the context for you. */ - static bool JUCE_CALLTYPE showNativeDialogBox (const String& title, - const String& bodyText, - bool isOkCancel); - - /** A set of colour IDs to use to change the colour of various aspects of the alert box. + static OpenGLContext* createContextForWindow (Component* componentToDrawTo, + const OpenGLPixelFormat& pixelFormat, + const OpenGLContext* const contextToShareWith); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + /** Returns the context that's currently in active use by the calling thread. - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + Returns 0 if there isn't an active context. */ - enum ColourIds - { - backgroundColourId = 0x1001800, /**< The background colour for the window. */ - textColourId = 0x1001810, /**< The colour for the text. */ - outlineColourId = 0x1001820 /**< An optional colour to use to draw a border around the window. */ - }; + static OpenGLContext* getCurrentContext(); juce_UseDebuggingNewOperator protected: - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - bool keyPressed (const KeyPress& key); - /** @internal */ - void buttonClicked (Button* button); - /** @internal */ - void lookAndFeelChanged(); - /** @internal */ - void userTriedToCloseWindow(); - /** @internal */ - int getDesktopWindowStyleFlags() const; - -private: - String text; - TextLayout textLayout; - AlertIconType alertIconType; - ComponentBoundsConstrainer constrainer; - ComponentDragger dragger; - Rectangle textArea; - VoidArray buttons, textBoxes, comboBoxes; - VoidArray progressBars, customComps, textBlocks, allComps; - StringArray textboxNames, comboBoxNames; - Font font; - Component* associatedComponent; - - void updateLayout (const bool onlyIncreaseSize); - - // disable copy constructor - AlertWindow (const AlertWindow&); - const AlertWindow& operator= (const AlertWindow&); + OpenGLContext() throw(); }; -#endif // __JUCE_ALERTWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_AlertWindow.h *********/ - -#endif -#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__ - -/********* Start of inlined file: juce_DialogWindow.h *********/ -#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__ -#define __JUCE_DIALOGWINDOW_JUCEHEADER__ - /** - A dialog-box style window. - - This class is a convenient way of creating a DocumentWindow with a close button - that can be triggered by pressing the escape key. - - Any of the methods available to a DocumentWindow or ResizableWindow are also - available to this, so it can be made resizable, have a menu bar, etc. - - To add items to the box, see the ResizableWindow::setContentComponent() method. - Don't add components directly to this class - always put them in a content component! + A component that contains an OpenGL canvas. - You'll need to override the DocumentWindow::closeButtonPressed() method to handle - the user clicking the close button - for more info, see the DocumentWindow - help. + Override this, add it to whatever component you want to, and use the renderOpenGL() + method to draw its contents. - @see DocumentWindow, ResizableWindow */ -class JUCE_API DialogWindow : public DocumentWindow +class JUCE_API OpenGLComponent : public Component { public: - /** Creates a DialogWindow. - - @param name the name to give the component - this is also - the title shown at the top of the window. To change - this later, use setName() - @param backgroundColour the colour to use for filling the window's background. - @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the - close button to be triggered - @param addToDesktop if true, the window will be automatically added to the - desktop; if false, you can use it as a child component + /** Creates an OpenGLComponent. */ - DialogWindow (const String& name, - const Colour& backgroundColour, - const bool escapeKeyTriggersCloseButton, - const bool addToDesktop = true); + OpenGLComponent(); - /** Destructor. + /** Destructor. */ + ~OpenGLComponent(); - If a content component has been set with setContentComponent(), it - will be deleted. - */ - ~DialogWindow(); + /** Changes the pixel format used by this component. - /** Easy way of quickly showing a dialog box containing a given component. + @see OpenGLPixelFormat::getAvailablePixelFormats() + */ + void setPixelFormat (const OpenGLPixelFormat& formatToUse); - This will open and display a DialogWindow containing a given component, returning - when the user clicks its close button. + /** Returns the pixel format that this component is currently using. */ + const OpenGLPixelFormat getPixelFormat() const; - It returns the value that was returned by the dialog box's runModalLoop() call. + /** Specifies an OpenGL context which should be shared with the one that this + component is using. - To close the dialog programatically, you should call exitModalState (returnValue) on - the DialogWindow that is created. To find a pointer to this window from your - contentComponent, you can do something like this: - @code - Dialogwindow* dw = contentComponent->findParentComponentOfClass ((DialogWindow*) 0); + This is an OpenGL feature that lets two contexts share their texture data. - if (dw != 0) - dw->exitModalState (1234); - @endcode + Note that this pointer is stored by the component, and when the component + needs to recreate its internal context for some reason, the same context + will be used again to share lists. So if you pass a context in here, + don't delete the context while this component is still using it! You can + call shareWith (0) to stop this component from sharing with it. + */ + void shareWith (OpenGLContext* contextToShareListsWith); - @param dialogTitle the dialog box's title - @param contentComponent the content component for the dialog box. Make sure - that this has been set to the size you want it to - be before calling this method. The component won't - be deleted by this call, so you can re-use it or delete - it afterwards - @param componentToCentreAround if this is non-zero, it indicates a component that - you'd like to show this dialog box in front of. See the - DocumentWindow::centreAroundComponent() method for more - info on this parameter - @param backgroundColour a colour to use for the dialog box's background colour - @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the - close button to be triggered - @param shouldBeResizable if true, the dialog window has either a resizable border, or - a corner resizer - @param useBottomRightCornerResizer if shouldBeResizable is true, this indicates whether - to use a border or corner resizer component. See ResizableWindow::setResizable() + /** Returns the context that this component is sharing with. + @see shareWith */ - static int showModalDialog (const String& dialogTitle, - Component* contentComponent, - Component* componentToCentreAround, - const Colour& backgroundColour, - const bool escapeKeyTriggersCloseButton, - const bool shouldBeResizable = false, - const bool useBottomRightCornerResizer = false); + OpenGLContext* getShareContext() const throw() { return contextToShareListsWith; } - juce_UseDebuggingNewOperator + /** Flips the openGL buffers over. */ + void swapBuffers(); -protected: - /** @internal */ - void resized(); + /** This replaces the normal paint() callback - use it to draw your openGL stuff. -private: - bool escapeKeyTriggersCloseButton; + When this is called, makeCurrentContextActive() will already have been called + for you, so you just need to draw. + */ + virtual void renderOpenGL() = 0; - DialogWindow (const DialogWindow&); - const DialogWindow& operator= (const DialogWindow&); -}; + /** This method is called when the component creates a new OpenGL context. -#endif // __JUCE_DIALOGWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_DialogWindow.h *********/ + A new context may be created when the component is first used, or when it + is moved to a different window, or when the window is hidden and re-shown, + etc. -#endif -#ifndef __JUCE_DOCUMENTWINDOW_JUCEHEADER__ + You can use this callback as an opportunity to set up things like textures + that your context needs. -#endif -#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__ + New contexts are created on-demand by the makeCurrentContextActive() method - so + if the context is deleted, e.g. by changing the pixel format or window, no context + will be created until the next call to makeCurrentContextActive(), which will + synchronously create one and call this method. This means that if you're using + a non-GUI thread for rendering, you can make sure this method is be called by + your renderer thread. -#endif -#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__ + When this callback happens, the context will already have been made current + using the makeCurrentContextActive() method, so there's no need to call it + again in your code. + */ + virtual void newOpenGLContextCreated() = 0; -/********* Start of inlined file: juce_SplashScreen.h *********/ -#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__ -#define __JUCE_SPLASHSCREEN_JUCEHEADER__ + /** Returns the context that will draw into this component. -/** A component for showing a splash screen while your app starts up. + This may return 0 if the component is currently invisible or hasn't currently + got a context. The context object can be deleted and a new one created during + the lifetime of this component, and there may be times when it doesn't have one. - This will automatically position itself, and delete itself when the app has - finished initialising (it uses the JUCEApplication::isInitialising() to detect - this). + @see newOpenGLContextCreated() + */ + OpenGLContext* getCurrentContext() const throw() { return context; } - To use it, just create one of these in your JUCEApplication::initialise() method, - call its show() method and let the object delete itself later. + /** Makes this component the current openGL context. - E.g. @code + You might want to use this in things like your resize() method, before calling + GL commands. - void MyApp::initialise (const String& commandLine) - { - SplashScreen* splash = new SplashScreen(); + If this returns false, then the context isn't active, so you should avoid + making any calls. - splash->show (T("welcome to my app"), - ImageCache::getFromFile (File ("/foobar/splash.jpg")), - 4000, false); + This call may actually create a context if one isn't currently initialised. If + it does this, it will also synchronously call the newOpenGLContextCreated() + method to let you initialise it as necessary. - .. no need to delete the splash screen - it'll do that itself. - } + @see OpenGLContext::makeActive + */ + bool makeCurrentContextActive(); - @endcode -*/ -class JUCE_API SplashScreen : public Component, - public Timer, - private DeletedAtShutdown -{ -public: + /** Stops the current component being the active OpenGL context. - /** Creates a SplashScreen object. + This is the opposite of makeCurrentContextActive() - After creating one of these (or your subclass of it), call one of the show() - methods to display it. + @see OpenGLContext::makeInactive */ - SplashScreen(); + void makeCurrentContextInactive(); - /** Destructor. */ - ~SplashScreen(); + /** Returns true if this component is the active openGL context for the + current thread. - /** Creates a SplashScreen object that will display an image. + @see OpenGLContext::isActive + */ + bool isActiveContext() const throw(); - As soon as this is called, the SplashScreen will be displayed in the centre of the - screen. This method will also dispatch any pending messages to make sure that when - it returns, the splash screen has been completely drawn, and your initialisation - code can carry on. + /** Calls the rendering callback, and swaps the buffers afterwards. - @param title the name to give the component - @param backgroundImage an image to draw on the component. The component's size - will be set to the size of this image, and if the image is - semi-transparent, the component will be made semi-transparent - too. This image will be deleted (or released from the ImageCache - if that's how it was created) by the splash screen object when - it is itself deleted. - @param minimumTimeToDisplayFor how long (in milliseconds) the splash screen - should stay visible for. If the initialisation takes longer than - this time, the splash screen will wait for it to finish before - disappearing, but if initialisation is very quick, this lets - you make sure that people get a good look at your splash. - @param useDropShadow if true, the window will have a drop shadow - @param removeOnMouseClick if true, the window will go away as soon as the user clicks - the mouse (anywhere) - */ - void show (const String& title, - Image* const backgroundImage, - const int minimumTimeToDisplayFor, - const bool useDropShadow, - const bool removeOnMouseClick = true); + This is called automatically by paint() when the component needs to be rendered. - /** Creates a SplashScreen object with a specified size. + It can be overridden if you need to decouple the rendering from the paint callback + and render with a custom thread. - For a custom splash screen, you can use this method to display it at a certain size - and then override the paint() method yourself to do whatever's necessary. + Returns true if the operation succeeded. + */ + virtual bool renderAndSwapBuffers(); - As soon as this is called, the SplashScreen will be displayed in the centre of the - screen. This method will also dispatch any pending messages to make sure that when - it returns, the splash screen has been completely drawn, and your initialisation - code can carry on. + /** This returns a critical section that can be used to lock the current context. - @param title the name to give the component - @param width the width to use - @param height the height to use - @param minimumTimeToDisplayFor how long (in milliseconds) the splash screen - should stay visible for. If the initialisation takes longer than - this time, the splash screen will wait for it to finish before - disappearing, but if initialisation is very quick, this lets - you make sure that people get a good look at your splash. - @param useDropShadow if true, the window will have a drop shadow - @param removeOnMouseClick if true, the window will go away as soon as the user clicks - the mouse (anywhere) + Because the context that is used by this component can change, e.g. when the + component is shown or hidden, then if you're rendering to it on a background + thread, this allows you to lock the context for the duration of your rendering + routine. */ - void show (const String& title, - const int width, - const int height, - const int minimumTimeToDisplayFor, - const bool useDropShadow, - const bool removeOnMouseClick = true); + CriticalSection& getContextLock() throw() { return contextLock; } /** @internal */ void paint (Graphics& g); - /** @internal */ - void timerCallback(); + + /** Returns the native handle of an embedded heavyweight window, if there is one. + + E.g. On windows, this will return the HWND of the sub-window containing + the opengl context, on the mac it'll be the NSOpenGLView. + */ + void* getNativeWindowHandle() const; juce_UseDebuggingNewOperator private: - Image* backgroundImage; - Time earliestTimeToDelete; - int originalClickCounter; - bool isImageInCache; + friend class OpenGLComponentWatcher; + OpenGLComponentWatcher* componentWatcher; - SplashScreen (const SplashScreen&); - const SplashScreen& operator= (const SplashScreen&); -}; + OpenGLContext* context; + OpenGLContext* contextToShareListsWith; -#endif // __JUCE_SPLASHSCREEN_JUCEHEADER__ -/********* End of inlined file: juce_SplashScreen.h *********/ + CriticalSection contextLock; + OpenGLPixelFormat preferredPixelFormat; + bool needToUpdateViewport; -#endif -#ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ + void deleteContext(); + void updateContextPosition(); + void internalRepaint (int x, int y, int w, int h); + + OpenGLComponent (const OpenGLComponent&); + const OpenGLComponent& operator= (const OpenGLComponent&); +}; #endif -#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__ +#endif // __JUCE_OPENGLCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_OpenGLComponent.h *********/ #endif -#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ +#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ -/********* Start of inlined file: juce_ThreadWithProgressWindow.h *********/ -#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ -#define __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ +/********* Start of inlined file: juce_PreferencesPanel.h *********/ +#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ +#define __JUCE_PREFERENCESPANEL_JUCEHEADER__ /** - A thread that automatically pops up a modal dialog box with a progress bar - and cancel button while it's busy running. - - These are handy for performing some sort of task while giving the user feedback - about how long there is to go, etc. - - E.g. @code - class MyTask : public ThreadWithProgressWindow - { - public: - MyTask() : ThreadWithProgressWindow (T("busy..."), true, true) - { - } - - ~MyTask() - { - } - - void run() - { - for (int i = 0; i < thingsToDo; ++i) - { - // must check this as often as possible, because this is - // how we know if the user's pressed 'cancel' - if (threadShouldExit()) - break; - - // this will update the progress bar on the dialog box - setProgress (i / (double) thingsToDo); - - // ... do the business here... - } - } - }; - - void doTheTask() - { - MyTask m; + A component with a set of buttons at the top for changing between pages of + preferences. - if (m.runThread()) - { - // thread finished normally.. - } - else - { - // user pressed the cancel button.. - } - } + This is just a handy way of writing a Mac-style preferences panel where you + have a row of buttons along the top for the different preference categories, + each button having an icon above its name. Clicking these will show an + appropriate prefs page below it. - @endcode + You can either put one of these inside your own component, or just use the + showInDialogBox() method to show it in a window and run it modally. - @see Thread, AlertWindow + To use it, just add a set of named pages with the addSettingsPage() method, + and implement the createComponentForPage() method to create suitable components + for each of these pages. */ -class JUCE_API ThreadWithProgressWindow : public Thread, - private Timer +class JUCE_API PreferencesPanel : public Component, + private ButtonListener { public: - /** Creates the thread. - - Initially, the dialog box won't be visible, it'll only appear when the - runThread() method is called. + /** Creates an empty panel. - @param windowTitle the title to go at the top of the dialog box - @param hasProgressBar whether the dialog box should have a progress bar (see - setProgress() ) - @param hasCancelButton whether the dialog box should have a cancel button - @param timeOutMsWhenCancelling when 'cancel' is pressed, this is how long to wait for - the thread to stop before killing it forcibly (see - Thread::stopThread() ) - @param cancelButtonText the text that should be shown in the cancel button - (if it has one) + Use addSettingsPage() to add some pages to it in your constructor. */ - ThreadWithProgressWindow (const String& windowTitle, - const bool hasProgressBar, - const bool hasCancelButton, - const int timeOutMsWhenCancelling = 10000, - const String& cancelButtonText = JUCE_T("Cancel")); + PreferencesPanel(); /** Destructor. */ - ~ThreadWithProgressWindow(); - - /** Starts the thread and waits for it to finish. + ~PreferencesPanel(); - This will start the thread, make the dialog box appear, and wait until either - the thread finishes normally, or until the cancel button is pressed. + /** Creates a page using a set of drawables to define the page's icon. - Before returning, the dialog box will be hidden. + Note that the other version of this method is much easier if you're using + an image instead of a custom drawable. - @param threadPriority the priority to use when starting the thread - see - Thread::startThread() for values - @returns true if the thread finished normally; false if the user pressed cancel + @param pageTitle the name of this preferences page - you'll need to + make sure your createComponentForPage() method creates + a suitable component when it is passed this name + @param normalIcon the drawable to display in the page's button normally + @param overIcon the drawable to display in the page's button when the mouse is over + @param downIcon the drawable to display in the page's button when the button is down + @see DrawableButton */ - bool runThread (const int threadPriority = 5); + void addSettingsPage (const String& pageTitle, + const Drawable* normalIcon, + const Drawable* overIcon, + const Drawable* downIcon); - /** The thread should call this periodically to update the position of the progress bar. + /** Creates a page using a set of drawables to define the page's icon. - @param newProgress the progress, from 0.0 to 1.0 - @see setStatusMessage + The other version of this method gives you more control over the icon, but this + one is much easier if you're just loading it from a file. + + @param pageTitle the name of this preferences page - you'll need to + make sure your createComponentForPage() method creates + a suitable component when it is passed this name + @param imageData a block of data containing an image file, e.g. a jpeg, png or gif. + For this to look good, you'll probably want to use a nice + transparent png file. + @param imageDataSize the size of the image data, in bytes */ - void setProgress (const double newProgress); + void addSettingsPage (const String& pageTitle, + const char* imageData, + const int imageDataSize); - /** The thread can call this to change the message that's displayed in the dialog box. + /** Utility method to display this panel in a DialogWindow. + + Calling this will create a DialogWindow containing this panel with the + given size and title, and will run it modally, returning when the user + closes the dialog box. */ - void setStatusMessage (const String& newStatusMessage); + void showInDialogBox (const String& dialogtitle, + int dialogWidth, + int dialogHeight, + const Colour& backgroundColour = Colours::white); - /** Returns the AlertWindow that is being used. + /** Subclasses must override this to return a component for each preferences page. + + The subclass should return a pointer to a new component representing the named + page, which the panel will then display. + + The panel will delete the component later when the user goes to another page + or deletes the panel. */ - AlertWindow* getAlertWindow() const throw() { return alertWindow; } + virtual Component* createComponentForPage (const String& pageName) = 0; + + /** Changes the current page being displayed. */ + void setCurrentPage (const String& pageName); + + /** @internal */ + void resized(); + /** @internal */ + void paint (Graphics& g); + /** @internal */ + void buttonClicked (Button* button); juce_UseDebuggingNewOperator private: - void timerCallback(); - double progress; - AlertWindow* alertWindow; - String message; - CriticalSection messageLock; - const int timeOutMsWhenCancelling; + String currentPageName; + Component* currentPage; + int buttonSize; - ThreadWithProgressWindow (const ThreadWithProgressWindow&); - const ThreadWithProgressWindow& operator= (const ThreadWithProgressWindow&); + PreferencesPanel (const PreferencesPanel&); + const PreferencesPanel& operator= (const PreferencesPanel&); }; -#endif // __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ -/********* End of inlined file: juce_ThreadWithProgressWindow.h *********/ +#endif // __JUCE_PREFERENCESPANEL_JUCEHEADER__ +/********* End of inlined file: juce_PreferencesPanel.h *********/ #endif -#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ +#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ -#endif -#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_QuickTimeMovieComponent.h *********/ +#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ +#define __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_ActiveXControlComponent.h *********/ -#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ -#define __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ +// (NB: This stuff mustn't go inside the "#if QUICKTIME" block, or it'll break the +// amalgamated build) +#if JUCE_WINDOWS -#if JUCE_WINDOWS || DOXYGEN + typedef ActiveXControlComponent QTCompBaseClass; +#elif JUCE_MAC -/** - A Windows-specific class that can create and embed an ActiveX control inside - itself. + typedef NSViewComponent QTCompBaseClass; +#endif - To use it, create one of these, put it in place and make sure it's visible in a - window, then use createControl() to instantiate an ActiveX control. The control - will then be moved and resized to follow the movements of this component. +// this is used to disable QuickTime, and is defined in juce_Config.h +#if JUCE_QUICKTIME || DOXYGEN + +/** + A window that can play back a QuickTime movie. - Of course, since the control is a heavyweight window, it'll obliterate any - juce components that may overlap this component, but that's life. */ -class JUCE_API ActiveXControlComponent : public Component +class JUCE_API QuickTimeMovieComponent : public QTCompBaseClass { public: - /** Create an initially-empty container. */ - ActiveXControlComponent(); - - /** Destructor. */ - ~ActiveXControlComponent(); - - /** Tries to create an ActiveX control and embed it in this peer. - - The peer controlIID is a pointer to an IID structure - it's treated - as a void* because when including the Juce headers, you might not always - have included windows.h first, in which case IID wouldn't be defined. - - e.g. @code - const IID myIID = __uuidof (QTControl); - myControlComp->createControl (&myIID); - @endcode - */ - bool createControl (const void* controlIID); + /** Creates a QuickTimeMovieComponent, initially blank. - /** Deletes the ActiveX control, if one has been created. + Use the loadMovie() method to load a movie once you've added the + component to a window, (or put it on the desktop as a heavyweight window). + Loading a movie when the component isn't visible can cause problems, as + QuickTime needs a window handle to initialise properly. */ - void deleteControl(); - - /** Returns true if a control is currently in use. */ - bool isControlOpen() const throw() { return control != 0; } - - /** Does a QueryInterface call on the embedded control object. - - This allows you to cast the control to whatever type of COM object you need. - - The iid parameter is a pointer to an IID structure - it's treated - as a void* because when including the Juce headers, you might not always - have included windows.h first, in which case IID wouldn't be defined, but - you should just pass a pointer to an IID. - - e.g. @code - const IID iid = __uuidof (IOleWindow); - - IOleWindow* oleWindow = (IOleWindow*) myControlComp->queryInterface (&iid); - - if (oleWindow != 0) - { - HWND hwnd; - oleWindow->GetWindow (&hwnd); + QuickTimeMovieComponent(); - ... + /** Destructor. */ + ~QuickTimeMovieComponent(); - oleWindow->Release(); - } - @endcode + /** Returns true if QT is installed and working on this machine. */ - void* queryInterface (const void* iid) const; + static bool isQuickTimeAvailable() throw(); - /** Set this to false to stop mouse events being allowed through to the control. - */ - void setMouseEventsAllowed (const bool eventsCanReachControl); + /** Tries to load a QuickTime movie from a file into the player. - /** Returns true if mouse events are allowed to get through to the control. + It's best to call this function once you've added the component to a window, + (or put it on the desktop as a heavyweight window). Loading a movie when the + component isn't visible can cause problems, because QuickTime needs a window + handle to do its stuff. + + @param movieFile the .mov file to open + @param isControllerVisible whether to show a controller bar at the bottom + @returns true if the movie opens successfully */ - bool areMouseEventsAllowed() const throw() { return mouseEventsAllowed; } + bool loadMovie (const File& movieFile, + const bool isControllerVisible); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void* originalWndProc; + /** Tries to load a QuickTime movie from a URL into the player. - juce_UseDebuggingNewOperator + It's best to call this function once you've added the component to a window, + (or put it on the desktop as a heavyweight window). Loading a movie when the + component isn't visible can cause problems, because QuickTime needs a window + handle to do its stuff. -private: - friend class ActiveXControlData; - void* control; - bool mouseEventsAllowed; + @param movieURL the .mov file to open + @param isControllerVisible whether to show a controller bar at the bottom + @returns true if the movie opens successfully + */ + bool loadMovie (const URL& movieURL, + const bool isControllerVisible); - ActiveXControlComponent (const ActiveXControlComponent&); - const ActiveXControlComponent& operator= (const ActiveXControlComponent&); + /** Tries to load a QuickTime movie from a stream into the player. - void setControlBounds (const Rectangle& bounds) const; - void setControlVisible (const bool b) const; -}; + It's best to call this function once you've added the component to a window, + (or put it on the desktop as a heavyweight window). Loading a movie when the + component isn't visible can cause problems, because QuickTime needs a window + handle to do its stuff. -#endif + @param movieStream a stream containing a .mov file. The component may try + to read the whole stream before playing, rather than + streaming from it. + @param isControllerVisible whether to show a controller bar at the bottom + @returns true if the movie opens successfully + */ + bool loadMovie (InputStream* movieStream, + const bool isControllerVisible); -#endif // __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_ActiveXControlComponent.h *********/ + /** Closes the movie, if one is open. */ + void closeMovie(); -#endif -#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ + /** Returns the movie file that is currently open. -/********* Start of inlined file: juce_AudioDeviceSelectorComponent.h *********/ -#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ -#define __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ + If there isn't one, this returns File::nonexistent + */ + const File getCurrentMovieFile() const; -class MidiInputSelectorComponentListBox; + /** Returns true if there's currently a movie open. */ + bool isMovieOpen() const; -/** - A component containing controls to let the user change the audio settings of - an AudioDeviceManager object. + /** Returns the length of the movie, in seconds. */ + double getMovieDuration() const; - Very easy to use - just create one of these and show it to the user. + /** Returns the movie's natural size, in pixels. - @see AudioDeviceManager -*/ -class JUCE_API AudioDeviceSelectorComponent : public Component, - public ComboBoxListener, - public ButtonListener, - public ChangeListener -{ -public: + You can use this to resize the component to show the movie at its preferred + scale. - /** Creates the component. + If no movie is loaded, the size returned will be 0 x 0. + */ + void getMovieNormalSize (int& width, int& height) const; - If your app needs only output channels, you might ask for a maximum of 0 input - channels, and the component won't display any options for choosing the input - channels. And likewise if you're doing an input-only app. + /** This will position the component within a given area, keeping its aspect + ratio correct according to the movie's normal size. - @param deviceManager the device manager that this component should control - @param minAudioInputChannels the minimum number of audio input channels that the application needs - @param maxAudioInputChannels the maximum number of audio input channels that the application needs - @param minAudioOutputChannels the minimum number of audio output channels that the application needs - @param maxAudioOutputChannels the maximum number of audio output channels that the application needs - @param showMidiInputOptions if true, the component will allow the user to select which midi inputs are enabled - @param showMidiOutputSelector if true, the component will let the user choose a default midi output device - @param showChannelsAsStereoPairs if true, channels will be treated as pairs; if false, channels will be - treated as a set of separate mono channels. - @param hideAdvancedOptionsWithButton if true, only the minimum amount of UI components - are shown, with an "advanced" button that shows the rest of them + The component will be made as large as it can go within the space, and will + be aligned according to the justification value if this means there are gaps at + the top or sides. */ - AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager, - const int minAudioInputChannels, - const int maxAudioInputChannels, - const int minAudioOutputChannels, - const int maxAudioOutputChannels, - const bool showMidiInputOptions, - const bool showMidiOutputSelector, - const bool showChannelsAsStereoPairs, - const bool hideAdvancedOptionsWithButton); + void setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin, + const RectanglePlacement& placement); - /** Destructor */ - ~AudioDeviceSelectorComponent(); + /** Starts the movie playing. */ + void play(); - /** @internal */ - void resized(); - /** @internal */ - void comboBoxChanged (ComboBox*); - /** @internal */ - void buttonClicked (Button*); - /** @internal */ - void changeListenerCallback (void*); - /** @internal */ - void childBoundsChanged (Component*); + /** Stops the movie playing. */ + void stop(); - juce_UseDebuggingNewOperator + /** Returns true if the movie is currently playing. */ + bool isPlaying() const; -private: - AudioDeviceManager& deviceManager; - ComboBox* deviceTypeDropDown; - Label* deviceTypeDropDownLabel; - Component* audioDeviceSettingsComp; - String audioDeviceSettingsCompType; - const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels; - const bool showChannelsAsStereoPairs; - const bool hideAdvancedOptionsWithButton; + /** Moves the movie's position back to the start. */ + void goToStart(); - MidiInputSelectorComponentListBox* midiInputsList; - Label* midiInputsLabel; - ComboBox* midiOutputSelector; - Label* midiOutputLabel; + /** Sets the movie's position to a given time. */ + void setPosition (const double seconds); - AudioDeviceSelectorComponent (const AudioDeviceSelectorComponent&); - const AudioDeviceSelectorComponent& operator= (const AudioDeviceSelectorComponent&); -}; + /** Returns the current play position of the movie. */ + double getPosition() const; -#endif // __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_AudioDeviceSelectorComponent.h *********/ + /** Changes the movie playback rate. -#endif -#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ + A value of 1 is normal speed, greater values play it proportionately faster, + smaller values play it slower. + */ + void setSpeed (const float newSpeed); -/********* Start of inlined file: juce_BubbleComponent.h *********/ -#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ -#define __JUCE_BUBBLECOMPONENT_JUCEHEADER__ + /** Changes the movie's playback volume. -/** - A component for showing a message or other graphics inside a speech-bubble-shaped - outline, pointing at a location on the screen. + @param newVolume the volume in the range 0 (silent) to 1.0 (full) + */ + void setMovieVolume (const float newVolume); - This is a base class that just draws and positions the bubble shape, but leaves - the drawing of any content up to a subclass. See BubbleMessageComponent for a subclass - that draws a text message. + /** Returns the movie's playback volume. - To use it, create your subclass, then either add it to a parent component or - put it on the desktop with addToDesktop (0), use setPosition() to - resize and position it, then make it visible. + @returns the volume in the range 0 (silent) to 1.0 (full) + */ + float getMovieVolume() const; - @see BubbleMessageComponent -*/ -class JUCE_API BubbleComponent : public Component -{ -protected: + /** Tells the movie whether it should loop. */ + void setLooping (const bool shouldLoop); - /** Creates a BubbleComponent. + /** Returns true if the movie is currently looping. - Your subclass will need to implement the getContentSize() and paintContent() - methods to draw the bubble's contents. + @see setLooping */ - BubbleComponent(); - -public: - /** Destructor. */ - ~BubbleComponent(); + bool isLooping() const; - /** A list of permitted placements for the bubble, relative to the co-ordinates - at which it should be pointing. + /** True if the native QuickTime controller bar is shown in the window. - @see setAllowedPlacement + @see loadMovie */ - enum BubblePlacement - { - above = 1, - below = 2, - left = 4, - right = 8 - }; + bool isControllerVisible() const; - /** Tells the bubble which positions it's allowed to put itself in, relative to the - point at which it's pointing. + /** @internal */ + void paint (Graphics& g); - By default when setPosition() is called, the bubble will place itself either - above, below, left, or right of the target area. You can pass in a bitwise-'or' of - the values in BubblePlacement to restrict this choice. + juce_UseDebuggingNewOperator - E.g. if you only want your bubble to appear above or below the target area, - use setAllowedPlacement (above | below); +private: + File movieFile; + bool movieLoaded, controllerVisible, looping; - @see BubblePlacement - */ - void setAllowedPlacement (const int newPlacement); +#if JUCE_WINDOWS + /** @internal */ + void parentHierarchyChanged(); + /** @internal */ + void visibilityChanged(); - /** Moves and resizes the bubble to point at a given component. + void createControlIfNeeded(); + bool isControlCreated() const; + void* internal; +#else + void* movie; +#endif - This will resize the bubble to fit its content, then find a position for it - so that it's next to, but doesn't overlap the given component. + QuickTimeMovieComponent (const QuickTimeMovieComponent&); + const QuickTimeMovieComponent& operator= (const QuickTimeMovieComponent&); +}; - It'll put itself either above, below, or to the side of the component depending - on where there's the most space, honouring any restrictions that were set - with setAllowedPlacement(). - */ - void setPosition (Component* componentToPointTo); +#endif +#endif // __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_QuickTimeMovieComponent.h *********/ - /** Moves and resizes the bubble to point at a given point. +#endif +#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ - This will resize the bubble to fit its content, then position it - so that the tip of the bubble points to the given co-ordinate. The co-ordinates - are relative to either the bubble component's parent component if it has one, or - they are screen co-ordinates if not. +/********* Start of inlined file: juce_SystemTrayIconComponent.h *********/ +#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ +#define __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ - It'll put itself either above, below, or to the side of this point, depending - on where there's the most space, honouring any restrictions that were set - with setAllowedPlacement(). - */ - void setPosition (const int arrowTipX, - const int arrowTipY); +#if JUCE_WINDOWS || JUCE_LINUX || DOXYGEN - /** Moves and resizes the bubble to point at a given rectangle. +/** + On Windows only, this component sits in the taskbar tray as a small icon. - This will resize the bubble to fit its content, then find a position for it - so that it's next to, but doesn't overlap the given rectangle. The rectangle's - co-ordinates are relative to either the bubble component's parent component - if it has one, or they are screen co-ordinates if not. + To use it, just create one of these components, but don't attempt to make it + visible, add it to a parent, or put it on the desktop. - It'll put itself either above, below, or to the side of the component depending - on where there's the most space, honouring any restrictions that were set - with setAllowedPlacement(). - */ - void setPosition (const Rectangle& rectangleToPointTo); + You can then call setIconImage() to create an icon for it in the taskbar. -protected: + To change the icon's tooltip, you can use setIconTooltip(). - /** Subclasses should override this to return the size of the content they - want to draw inside the bubble. - */ - virtual void getContentSize (int& width, int& height) = 0; + To respond to mouse-events, you can override the normal mouseDown(), + mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y + position will not be valid, you can use this to respond to clicks. Traditionally + you'd use a left-click to show your application's window, and a right-click + to show a pop-up menu. +*/ +class JUCE_API SystemTrayIconComponent : public Component +{ +public: - /** Subclasses should override this to draw their bubble's contents. + SystemTrayIconComponent(); - The graphics object's clip region and the dimensions passed in here are - set up to paint just the rectangle inside the bubble. + /** Destructor. */ + ~SystemTrayIconComponent(); + + /** Changes the image shown in the taskbar. */ - virtual void paintContent (Graphics& g, int width, int height) = 0; + void setIconImage (const Image& newImage); -public: + /** Changes the tooltip that Windows shows above the icon. */ + void setIconTooltip (const String& tooltip); +#if JUCE_LINUX /** @internal */ void paint (Graphics& g); +#endif juce_UseDebuggingNewOperator private: - Rectangle content; - int side, allowablePlacements; - float arrowTipX, arrowTipY; - DropShadowEffect shadow; - BubbleComponent (const BubbleComponent&); - const BubbleComponent& operator= (const BubbleComponent&); + SystemTrayIconComponent (const SystemTrayIconComponent&); + const SystemTrayIconComponent& operator= (const SystemTrayIconComponent&); }; -#endif // __JUCE_BUBBLECOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_BubbleComponent.h *********/ +#endif +#endif // __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_SystemTrayIconComponent.h *********/ #endif -#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ +#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ -/********* Start of inlined file: juce_BubbleMessageComponent.h *********/ -#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ -#define __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_WebBrowserComponent.h *********/ +#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ +#define __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ + +#if JUCE_WEB_BROWSER || DOXYGEN + +#if ! DOXYGEN + class WebBrowserComponentInternal; +#endif /** - A speech-bubble component that displays a short message. + A component that displays an embedded web browser. - This can be used to show a message with the tail of the speech bubble - pointing to a particular component or location on the screen. + The browser itself will be platform-dependent. On the Mac, probably Safari, on + Windows, probably IE. - @see BubbleComponent */ -class JUCE_API BubbleMessageComponent : public BubbleComponent, - private Timer +class JUCE_API WebBrowserComponent : public Component { public: - /** Creates a bubble component. + /** Creates a WebBrowserComponent. - After creating one a BubbleComponent, do the following: - - add it to an appropriate parent component, or put it on the - desktop with Component::addToDesktop (0). - - use the showAt() method to show a message. - - it will make itself invisible after it times-out (and can optionally - also delete itself), or you can reuse it somewhere else by calling - showAt() again. + Once it's created and visible, send the browser to a URL using goToURL(). + + @param unloadPageWhenBrowserIsHidden if this is true, then when the browser + component is taken offscreen, it'll clear the current page + and replace it with a blank page - this can be handy to stop + the browser using resources in the background when it's not + actually being used. */ - BubbleMessageComponent (const int fadeOutLengthMs = 150); + WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden = true); /** Destructor. */ - ~BubbleMessageComponent(); + ~WebBrowserComponent(); - /** Shows a message bubble at a particular position. + /** Sends the browser to a particular URL. - This shows the bubble with its stem pointing to the given location - (co-ordinates being relative to its parent component). + @param url the URL to go to. + @param headers an optional set of parameters to put in the HTTP header. If + you supply this, it should be a set of string in the form + "HeaderKey: HeaderValue" + @param postData an optional block of data that will be attached to the HTTP + POST request + */ + void goToURL (const String& url, + const StringArray* headers = 0, + const MemoryBlock* postData = 0); - For details about exactly how it decides where to position itself, see - BubbleComponent::updatePosition(). + /** Stops the current page loading. + */ + void stop(); - @param x the x co-ordinate of end of the bubble's tail - @param y the y co-ordinate of end of the bubble's tail - @param message the text to display - @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself - from its parent compnent. If this is 0 or less, it - will stay there until manually removed. - @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a - mouse button is pressed (anywhere on the screen) - @param deleteSelfAfterUse if true, then the component will delete itself after - it becomes invisible + /** Sends the browser back one page. */ - void showAt (int x, int y, - const String& message, - const int numMillisecondsBeforeRemoving, - const bool removeWhenMouseClicked = true, - const bool deleteSelfAfterUse = false); + void goBack(); - /** Shows a message bubble next to a particular component. + /** Sends the browser forward one page. + */ + void goForward(); - This shows the bubble with its stem pointing at the given component. + /** Refreshes the browser. + */ + void refresh(); - For details about exactly how it decides where to position itself, see - BubbleComponent::updatePosition(). + /** This callback is called when the browser is about to navigate + to a new location. - @param component the component that you want to point at - @param message the text to display - @param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself - from its parent compnent. If this is 0 or less, it - will stay there until manually removed. - @param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a - mouse button is pressed (anywhere on the screen) - @param deleteSelfAfterUse if true, then the component will delete itself after - it becomes invisible + You can override this method to perform some action when the user + tries to go to a particular URL. To allow the operation to carry on, + return true, or return false to stop the navigation happening. */ - void showAt (Component* const component, - const String& message, - const int numMillisecondsBeforeRemoving, - const bool removeWhenMouseClicked = true, - const bool deleteSelfAfterUse = false); + virtual bool pageAboutToLoad (const String& newURL); /** @internal */ - void getContentSize (int& w, int& h); + void paint (Graphics& g); /** @internal */ - void paintContent (Graphics& g, int w, int h); + void resized(); /** @internal */ - void timerCallback(); + void parentHierarchyChanged(); + /** @internal */ + void visibilityChanged(); juce_UseDebuggingNewOperator private: - int fadeOutLength, mouseClickCounter; - TextLayout textLayout; - int64 expiryTime; - bool deleteAfterUse; + WebBrowserComponentInternal* browser; + bool blankPageShown, unloadPageWhenBrowserIsHidden; + String lastURL; + StringArray lastHeaders; + MemoryBlock lastPostData; - void init (const int numMillisecondsBeforeRemoving, - const bool removeWhenMouseClicked, - const bool deleteSelfAfterUse); + void reloadLastURL(); + void checkWindowAssociation(); - BubbleMessageComponent (const BubbleMessageComponent&); - const BubbleMessageComponent& operator= (const BubbleMessageComponent&); + WebBrowserComponent (const WebBrowserComponent&); + const WebBrowserComponent& operator= (const WebBrowserComponent&); }; -#endif // __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_BubbleMessageComponent.h *********/ - #endif -#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ - -/********* Start of inlined file: juce_ColourSelector.h *********/ -#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ -#define __JUCE_COLOURSELECTOR_JUCEHEADER__ - -/** - A component that lets the user choose a colour. - - This shows RGB sliders and a colourspace that the user can pick colours from. - - This class is also a ChangeBroadcaster, so listeners can register to be told - when the colour changes. -*/ -class JUCE_API ColourSelector : public Component, - public ChangeBroadcaster, - protected SliderListener -{ -public: - - /** Options for the type of selector to show. These are passed into the constructor. */ - enum ColourSelectorOptions - { - showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */ +#endif // __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ +/********* End of inlined file: juce_WebBrowserComponent.h *********/ - showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */ - showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */ - showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */ - }; +#endif +#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ - /** Creates a ColourSelector object. +#endif +#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ - The flags are a combination of values from the ColourSelectorOptions enum, specifying - which of the selector's features should be visible. +#endif +#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__ - The edgeGap value specifies the amount of space to leave around the edge. +/********* Start of inlined file: juce_DialogWindow.h *********/ +#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__ +#define __JUCE_DIALOGWINDOW_JUCEHEADER__ - gapAroundColourSpaceComponent indicates how much of a gap to put around the - colourspace and hue selector components. - */ - ColourSelector (const int sectionsToShow = (showAlphaChannel | showColourAtTop | showSliders | showColourspace), - const int edgeGap = 4, - const int gapAroundColourSpaceComponent = 7); +/** + A dialog-box style window. - /** Destructor. */ - ~ColourSelector(); + This class is a convenient way of creating a DocumentWindow with a close button + that can be triggered by pressing the escape key. - /** Returns the colour that the user has currently selected. + Any of the methods available to a DocumentWindow or ResizableWindow are also + available to this, so it can be made resizable, have a menu bar, etc. - The ColourSelector class is also a ChangeBroadcaster, so listeners can - register to be told when the colour changes. + To add items to the box, see the ResizableWindow::setContentComponent() method. + Don't add components directly to this class - always put them in a content component! - @see setCurrentColour - */ - const Colour getCurrentColour() const; + You'll need to override the DocumentWindow::closeButtonPressed() method to handle + the user clicking the close button - for more info, see the DocumentWindow + help. - /** Changes the colour that is currently being shown. - */ - void setCurrentColour (const Colour& newColour); + @see DocumentWindow, ResizableWindow +*/ +class JUCE_API DialogWindow : public DocumentWindow +{ +public: - /** Tells the selector how many preset colour swatches you want to have on the component. + /** Creates a DialogWindow. - To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and - setSwatchColour(), to return the number of colours you want, and to set and retrieve - their values. + @param name the name to give the component - this is also + the title shown at the top of the window. To change + this later, use setName() + @param backgroundColour the colour to use for filling the window's background. + @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the + close button to be triggered + @param addToDesktop if true, the window will be automatically added to the + desktop; if false, you can use it as a child component */ - virtual int getNumSwatches() const; - - /** Called by the selector to find out the colour of one of the swatches. + DialogWindow (const String& name, + const Colour& backgroundColour, + const bool escapeKeyTriggersCloseButton, + const bool addToDesktop = true); - Your subclass should return the colour of the swatch with the given index. + /** Destructor. - To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and - setSwatchColour(), to return the number of colours you want, and to set and retrieve - their values. + If a content component has been set with setContentComponent(), it + will be deleted. */ - virtual const Colour getSwatchColour (const int index) const; + ~DialogWindow(); - /** Called by the selector when the user puts a new colour into one of the swatches. + /** Easy way of quickly showing a dialog box containing a given component. - Your subclass should change the colour of the swatch with the given index. + This will open and display a DialogWindow containing a given component, returning + when the user clicks its close button. - To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and - setSwatchColour(), to return the number of colours you want, and to set and retrieve - their values. - */ - virtual void setSwatchColour (const int index, const Colour& newColour) const; + It returns the value that was returned by the dialog box's runModalLoop() call. - /** A set of colour IDs to use to change the colour of various aspects of the keyboard. + To close the dialog programatically, you should call exitModalState (returnValue) on + the DialogWindow that is created. To find a pointer to this window from your + contentComponent, you can do something like this: + @code + Dialogwindow* dw = contentComponent->findParentComponentOfClass ((DialogWindow*) 0); - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. + if (dw != 0) + dw->exitModalState (1234); + @endcode - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour + @param dialogTitle the dialog box's title + @param contentComponent the content component for the dialog box. Make sure + that this has been set to the size you want it to + be before calling this method. The component won't + be deleted by this call, so you can re-use it or delete + it afterwards + @param componentToCentreAround if this is non-zero, it indicates a component that + you'd like to show this dialog box in front of. See the + DocumentWindow::centreAroundComponent() method for more + info on this parameter + @param backgroundColour a colour to use for the dialog box's background colour + @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the + close button to be triggered + @param shouldBeResizable if true, the dialog window has either a resizable border, or + a corner resizer + @param useBottomRightCornerResizer if shouldBeResizable is true, this indicates whether + to use a border or corner resizer component. See ResizableWindow::setResizable() */ - enum ColourIds - { - backgroundColourId = 0x1007000, /**< the colour used to fill the component's background. */ - labelTextColourId = 0x1007001 /**< the colour used for the labels next to the sliders. */ - }; + static int showModalDialog (const String& dialogTitle, + Component* contentComponent, + Component* componentToCentreAround, + const Colour& backgroundColour, + const bool escapeKeyTriggersCloseButton, + const bool shouldBeResizable = false, + const bool useBottomRightCornerResizer = false); juce_UseDebuggingNewOperator -private: - friend class ColourSpaceView; - friend class HueSelectorComp; - Colour colour; - float h, s, v; - Slider* sliders[4]; - Component* colourSpace; - Component* hueSelector; - VoidArray swatchComponents; - const int flags; - int topSpace, edgeGap; - - void setHue (float newH); - void setSV (float newS, float newV); - void updateHSV(); - void update(); - void sliderValueChanged (Slider*); - void paint (Graphics& g); +protected: + /** @internal */ void resized(); - ColourSelector (const ColourSelector&); - const ColourSelector& operator= (const ColourSelector&); +private: + bool escapeKeyTriggersCloseButton; - // this constructor is here temporarily to prevent old code compiling, because the parameters - // have changed - if you get an error here, update your code to use the new constructor instead.. - // (xxx - note to self: remember to remove this at some point in the future) - ColourSelector (const bool); + DialogWindow (const DialogWindow&); + const DialogWindow& operator= (const DialogWindow&); }; -#endif // __JUCE_COLOURSELECTOR_JUCEHEADER__ -/********* End of inlined file: juce_ColourSelector.h *********/ +#endif // __JUCE_DIALOGWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_DialogWindow.h *********/ #endif -#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ +#ifndef __JUCE_DOCUMENTWINDOW_JUCEHEADER__ #endif -#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__ -/********* Start of inlined file: juce_MagnifierComponent.h *********/ -#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ -#define __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__ -/** - A component that contains another component, and can magnify or shrink it. +/********* Start of inlined file: juce_SplashScreen.h *********/ +#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__ +#define __JUCE_SPLASHSCREEN_JUCEHEADER__ - This component will continually update its size so that it fits the zoomed - version of the content component that you put inside it, so don't try to - change the size of this component directly - instead change that of the - content component. +/** A component for showing a splash screen while your app starts up. - To make it all work, the magnifier uses extremely cunning ComponentPeer tricks - to remap mouse events correctly. This means that the content component won't - appear to be a direct child of this component, and instead will think its - on the desktop. + This will automatically position itself, and delete itself when the app has + finished initialising (it uses the JUCEApplication::isInitialising() to detect + this). + + To use it, just create one of these in your JUCEApplication::initialise() method, + call its show() method and let the object delete itself later. + + E.g. @code + + void MyApp::initialise (const String& commandLine) + { + SplashScreen* splash = new SplashScreen(); + + splash->show (T("welcome to my app"), + ImageCache::getFromFile (File ("/foobar/splash.jpg")), + 4000, false); + + .. no need to delete the splash screen - it'll do that itself. + } + + @endcode */ -class JUCE_API MagnifierComponent : public Component +class JUCE_API SplashScreen : public Component, + public Timer, + private DeletedAtShutdown { public: - /** Creates a MagnifierComponent. - - This component will continually update its size so that it fits the zoomed - version of the content component that you put inside it, so don't try to - change the size of this component directly - instead change that of the - content component. + /** Creates a SplashScreen object. - @param contentComponent the component to add as the magnified one - @param deleteContentCompWhenNoLongerNeeded if true, the content component will - be deleted when this component is deleted. If false, - it's the caller's responsibility to delete it later. + After creating one of these (or your subclass of it), call one of the show() + methods to display it. */ - MagnifierComponent (Component* const contentComponent, - const bool deleteContentCompWhenNoLongerNeeded); + SplashScreen(); /** Destructor. */ - ~MagnifierComponent(); - - /** Returns the current content component. */ - Component* getContentComponent() const throw() { return content; } + ~SplashScreen(); - /** Changes the zoom level. + /** Creates a SplashScreen object that will display an image. - The scale factor must be greater than zero. Values less than 1 will shrink the - image; values greater than 1 will multiply its size by this amount. + As soon as this is called, the SplashScreen will be displayed in the centre of the + screen. This method will also dispatch any pending messages to make sure that when + it returns, the splash screen has been completely drawn, and your initialisation + code can carry on. - When this is called, this component will change its size to fit the full extent - of the newly zoomed content. + @param title the name to give the component + @param backgroundImage an image to draw on the component. The component's size + will be set to the size of this image, and if the image is + semi-transparent, the component will be made semi-transparent + too. This image will be deleted (or released from the ImageCache + if that's how it was created) by the splash screen object when + it is itself deleted. + @param minimumTimeToDisplayFor how long (in milliseconds) the splash screen + should stay visible for. If the initialisation takes longer than + this time, the splash screen will wait for it to finish before + disappearing, but if initialisation is very quick, this lets + you make sure that people get a good look at your splash. + @param useDropShadow if true, the window will have a drop shadow + @param removeOnMouseClick if true, the window will go away as soon as the user clicks + the mouse (anywhere) */ - void setScaleFactor (double newScaleFactor); - - /** Returns the current zoom factor. */ - double getScaleFactor() const throw() { return scaleFactor; } + void show (const String& title, + Image* const backgroundImage, + const int minimumTimeToDisplayFor, + const bool useDropShadow, + const bool removeOnMouseClick = true); - /** Changes the quality setting used to rescale the graphics. - */ - void setResamplingQuality (Graphics::ResamplingQuality newQuality); + /** Creates a SplashScreen object with a specified size. - juce_UseDebuggingNewOperator + For a custom splash screen, you can use this method to display it at a certain size + and then override the paint() method yourself to do whatever's necessary. - /** @internal */ - void childBoundsChanged (Component*); + As soon as this is called, the SplashScreen will be displayed in the centre of the + screen. This method will also dispatch any pending messages to make sure that when + it returns, the splash screen has been completely drawn, and your initialisation + code can carry on. -private: - Component* content; - Component* holderComp; - double scaleFactor; - ComponentPeer* peer; - bool deleteContent; - Graphics::ResamplingQuality quality; + @param title the name to give the component + @param width the width to use + @param height the height to use + @param minimumTimeToDisplayFor how long (in milliseconds) the splash screen + should stay visible for. If the initialisation takes longer than + this time, the splash screen will wait for it to finish before + disappearing, but if initialisation is very quick, this lets + you make sure that people get a good look at your splash. + @param useDropShadow if true, the window will have a drop shadow + @param removeOnMouseClick if true, the window will go away as soon as the user clicks + the mouse (anywhere) + */ + void show (const String& title, + const int width, + const int height, + const int minimumTimeToDisplayFor, + const bool useDropShadow, + const bool removeOnMouseClick = true); + /** @internal */ void paint (Graphics& g); - void mouseDown (const MouseEvent& e); - void mouseUp (const MouseEvent& e); - void mouseDrag (const MouseEvent& e); - void mouseMove (const MouseEvent& e); - void mouseEnter (const MouseEvent& e); - void mouseExit (const MouseEvent& e); - void mouseWheelMove (const MouseEvent& e, float, float); + /** @internal */ + void timerCallback(); - int scaleInt (const int n) const throw(); + juce_UseDebuggingNewOperator - MagnifierComponent (const MagnifierComponent&); - const MagnifierComponent& operator= (const MagnifierComponent&); +private: + Image* backgroundImage; + Time earliestTimeToDelete; + int originalClickCounter; + bool isImageInCache; + + SplashScreen (const SplashScreen&); + const SplashScreen& operator= (const SplashScreen&); }; -#endif // __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_MagnifierComponent.h *********/ +#endif // __JUCE_SPLASHSCREEN_JUCEHEADER__ +/********* End of inlined file: juce_SplashScreen.h *********/ #endif -#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ -/********* Start of inlined file: juce_MidiKeyboardComponent.h *********/ -#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ -#define __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ +/********* Start of inlined file: juce_ThreadWithProgressWindow.h *********/ +#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ +#define __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ /** - A component that displays a piano keyboard, whose notes can be clicked on. + A thread that automatically pops up a modal dialog box with a progress bar + and cancel button while it's busy running. - This component will mimic a physical midi keyboard, showing the current state of - a MidiKeyboardState object. When the on-screen keys are clicked on, it will play these - notes by calling the noteOn() and noteOff() methods of its MidiKeyboardState object. + These are handy for performing some sort of task while giving the user feedback + about how long there is to go, etc. - Another feature is that the computer keyboard can also be used to play notes. By - default it maps the top two rows of a standard querty keyboard to the notes, but - these can be remapped if needed. It will only respond to keypresses when it has - the keyboard focus, so to disable this feature you can call setWantsKeyboardFocus (false). + E.g. @code + class MyTask : public ThreadWithProgressWindow + { + public: + MyTask() : ThreadWithProgressWindow (T("busy..."), true, true) + { + } - The component is also a ChangeBroadcaster, so if you want to be informed when the - keyboard is scrolled, you can register a ChangeListener for callbacks. + ~MyTask() + { + } - @see MidiKeyboardState + void run() + { + for (int i = 0; i < thingsToDo; ++i) + { + // must check this as often as possible, because this is + // how we know if the user's pressed 'cancel' + if (threadShouldExit()) + break; + + // this will update the progress bar on the dialog box + setProgress (i / (double) thingsToDo); + + // ... do the business here... + } + } + }; + + void doTheTask() + { + MyTask m; + + if (m.runThread()) + { + // thread finished normally.. + } + else + { + // user pressed the cancel button.. + } + } + + @endcode + + @see Thread, AlertWindow */ -class JUCE_API MidiKeyboardComponent : public Component, - public MidiKeyboardStateListener, - public ChangeBroadcaster, - private Timer, - private AsyncUpdater +class JUCE_API ThreadWithProgressWindow : public Thread, + private Timer { public: - /** The direction of the keyboard. - - @see setOrientation - */ - enum Orientation - { - horizontalKeyboard, - verticalKeyboardFacingLeft, - verticalKeyboardFacingRight, - }; + /** Creates the thread. - /** Creates a MidiKeyboardComponent. + Initially, the dialog box won't be visible, it'll only appear when the + runThread() method is called. - @param state the midi keyboard model that this component will represent - @param orientation whether the keyboard is horizonal or vertical + @param windowTitle the title to go at the top of the dialog box + @param hasProgressBar whether the dialog box should have a progress bar (see + setProgress() ) + @param hasCancelButton whether the dialog box should have a cancel button + @param timeOutMsWhenCancelling when 'cancel' is pressed, this is how long to wait for + the thread to stop before killing it forcibly (see + Thread::stopThread() ) + @param cancelButtonText the text that should be shown in the cancel button + (if it has one) */ - MidiKeyboardComponent (MidiKeyboardState& state, - const Orientation orientation); + ThreadWithProgressWindow (const String& windowTitle, + const bool hasProgressBar, + const bool hasCancelButton, + const int timeOutMsWhenCancelling = 10000, + const String& cancelButtonText = JUCE_T("Cancel")); /** Destructor. */ - ~MidiKeyboardComponent(); + ~ThreadWithProgressWindow(); - /** Changes the velocity used in midi note-on messages that are triggered by clicking - on the component. + /** Starts the thread and waits for it to finish. - Values are 0 to 1.0, where 1.0 is the heaviest. + This will start the thread, make the dialog box appear, and wait until either + the thread finishes normally, or until the cancel button is pressed. - @see setMidiChannel + Before returning, the dialog box will be hidden. + + @param threadPriority the priority to use when starting the thread - see + Thread::startThread() for values + @returns true if the thread finished normally; false if the user pressed cancel */ - void setVelocity (const float velocity, const bool useMousePositionForVelocity); + bool runThread (const int threadPriority = 5); - /** Changes the midi channel number that will be used for events triggered by clicking - on the component. + /** The thread should call this periodically to update the position of the progress bar. - The channel must be between 1 and 16 (inclusive). This is the channel that will be - passed on to the MidiKeyboardState::noteOn() method when the user clicks the component. + @param newProgress the progress, from 0.0 to 1.0 + @see setStatusMessage + */ + void setProgress (const double newProgress); - Although this is the channel used for outgoing events, the component can display - incoming events from more than one channel - see setMidiChannelsToDisplay() + /** The thread can call this to change the message that's displayed in the dialog box. + */ + void setStatusMessage (const String& newStatusMessage); - @see setVelocity + /** Returns the AlertWindow that is being used. */ - void setMidiChannel (const int midiChannelNumber); + AlertWindow* getAlertWindow() const throw() { return alertWindow; } - /** Returns the midi channel that the keyboard is using for midi messages. + juce_UseDebuggingNewOperator - @see setMidiChannel - */ - int getMidiChannel() const throw() { return midiChannel; } +private: + void timerCallback(); - /** Sets a mask to indicate which incoming midi channels should be represented by - key movements. + double progress; + AlertWindow* alertWindow; + String message; + CriticalSection messageLock; + const int timeOutMsWhenCancelling; - The mask is a set of bits, where bit 0 = midi channel 1, bit 1 = midi channel 2, etc. + ThreadWithProgressWindow (const ThreadWithProgressWindow&); + const ThreadWithProgressWindow& operator= (const ThreadWithProgressWindow&); +}; - If the MidiKeyboardState has a key down for any of the channels whose bits are set - in this mask, the on-screen keys will also go down. +#endif // __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ +/********* End of inlined file: juce_ThreadWithProgressWindow.h *********/ - By default, this mask is set to 0xffff (all channels displayed). +#endif +#ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ - @see setMidiChannel - */ - void setMidiChannelsToDisplay (const int midiChannelMask); +#endif +#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__ - /** Returns the current set of midi channels represented by the component. +#endif +#ifndef __JUCE_COLOUR_JUCEHEADER__ - This is the value that was set with setMidiChannelsToDisplay(). - */ - int getMidiChannelsToDisplay() const throw() { return midiInChannelMask; } +#endif +#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ - /** Changes the width used to draw the white keys. */ - void setKeyWidth (const float widthInPixels); +#endif +#ifndef __JUCE_COLOURS_JUCEHEADER__ - /** Returns the width that was set by setKeyWidth(). */ - float getKeyWidth() const throw() { return keyWidth; } +#endif +#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ - /** Changes the keyboard's current direction. */ - void setOrientation (const Orientation newOrientation); +#endif +#ifndef __JUCE_EDGETABLE_JUCEHEADER__ - /** Returns the keyboard's current direction. */ - const Orientation getOrientation() const throw() { return orientation; } +#endif +#ifndef __JUCE_FILLTYPE_JUCEHEADER__ + +#endif +#ifndef __JUCE_GRAPHICS_JUCEHEADER__ + +#endif +#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ + +#endif +#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ + +/********* Start of inlined file: juce_LowLevelGraphicsContext.h *********/ +#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ +#define __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ + +/** + Interface class for graphics context objects, used internally by the Graphics class. + + Users are not supposed to create instances of this class directly - do your drawing + via the Graphics object instead. + + It's a base class for different types of graphics context, that may perform software-based + or OS-accelerated rendering. + + E.g. the LowLevelGraphicsSoftwareRenderer renders onto an image in memory, but other + subclasses could render directly to a windows HDC, a Quartz context, or an OpenGL + context. +*/ +class JUCE_API LowLevelGraphicsContext +{ +protected: - /** Sets the range of midi notes that the keyboard will be limited to. + LowLevelGraphicsContext(); - By default the range is 0 to 127 (inclusive), but you can limit this if you - only want a restricted set of the keys to be shown. +public: + virtual ~LowLevelGraphicsContext(); - Note that the values here are inclusive and must be between 0 and 127. - */ - void setAvailableRange (const int lowestNote, - const int highestNote); + /** Returns true if this device is vector-based, e.g. a printer. */ + virtual bool isVectorDevice() const = 0; - /** Returns the first note in the available range. + /** Moves the origin to a new position. - @see setAvailableRange + The co-ords are relative to the current origin, and indicate the new position + of (0, 0). */ - int getRangeStart() const throw() { return rangeStart; } + virtual void setOrigin (int x, int y) = 0; - /** Returns the last note in the available range. + virtual bool clipToRectangle (const Rectangle& r) = 0; + virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; + virtual void excludeClipRectangle (const Rectangle& r) = 0; + virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0; + virtual void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) = 0; - @see setAvailableRange - */ - int getRangeEnd() const throw() { return rangeEnd; } + virtual bool clipRegionIntersects (const Rectangle& r) = 0; + virtual const Rectangle getClipBounds() const = 0; + virtual bool isClipEmpty() const = 0; - /** If the keyboard extends beyond the size of the component, this will scroll - it to show the given key at the start. + virtual void saveState() = 0; + virtual void restoreState() = 0; - Whenever the keyboard's position is changed, this will use the ChangeBroadcaster - base class to send a callback to any ChangeListeners that have been registered. - */ - void setLowestVisibleKey (int noteNumber); + virtual void setFill (const FillType& fillType) = 0; + virtual void setOpacity (float newOpacity) = 0; + virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0; - /** Returns the number of the first key shown in the component. + virtual void fillRect (const Rectangle& r, const bool replaceExistingContents) = 0; + virtual void fillPath (const Path& path, const AffineTransform& transform) = 0; - @see setLowestVisibleKey - */ - int getLowestVisibleKey() const throw() { return firstKey; } + virtual void drawImage (const Image& sourceImage, const Rectangle& srcClip, + const AffineTransform& transform, const bool fillEntireClipAsTiles) = 0; - /** Returns the length of the black notes. + virtual void drawLine (double x1, double y1, double x2, double y2) = 0; + virtual void drawVerticalLine (const int x, double top, double bottom) = 0; + virtual void drawHorizontalLine (const int y, double left, double right) = 0; - This will be their vertical or horizontal length, depending on the keyboard's orientation. - */ - int getBlackNoteLength() const throw() { return blackNoteLength; } + virtual void setFont (const Font& newFont) = 0; + virtual const Font getFont() = 0; + virtual void drawGlyph (int glyphNumber, const AffineTransform& transform) = 0; +}; - /** If set to true, then scroll buttons will appear at either end of the keyboard - if there are too many notes to fit them all in the component at once. - */ - void setScrollButtonsVisible (const bool canScroll); +#endif // __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ +/********* End of inlined file: juce_LowLevelGraphicsContext.h *********/ - /** A set of colour IDs to use to change the colour of various aspects of the keyboard. +#endif +#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. +/********* Start of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h *********/ +#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ +#define __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - whiteNoteColourId = 0x1005000, - blackNoteColourId = 0x1005001, - keySeparatorLineColourId = 0x1005002, - mouseOverKeyOverlayColourId = 0x1005003, /**< This colour will be overlaid on the normal note colour. */ - keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */ - textLabelColourId = 0x1005005, - upDownButtonBackgroundColourId = 0x1005006, - upDownButtonArrowColourId = 0x1005007 - }; +/** + An implementation of LowLevelGraphicsContext that turns the drawing operations + into a PostScript document. - /** Returns the position within the component of the left-hand edge of a key. +*/ +class JUCE_API LowLevelGraphicsPostScriptRenderer : public LowLevelGraphicsContext +{ +public: - Depending on the keyboard's orientation, this may be a horizontal or vertical - distance, in either direction. - */ - int getKeyStartPosition (const int midiNoteNumber) const; + LowLevelGraphicsPostScriptRenderer (OutputStream& resultingPostScript, + const String& documentTitle, + const int totalWidth, + const int totalHeight); - /** Deletes all key-mappings. + ~LowLevelGraphicsPostScriptRenderer(); - @see setKeyPressForNote - */ - void clearKeyMappings(); + bool isVectorDevice() const; + void setOrigin (int x, int y); - /** Maps a key-press to a given note. + bool clipToRectangle (const Rectangle& r); + bool clipToRectangleList (const RectangleList& clipRegion); + void excludeClipRectangle (const Rectangle& r); + void clipToPath (const Path& path, const AffineTransform& transform); + void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); - @param key the key that should trigger the note - @param midiNoteOffsetFromC how many semitones above C the triggered note should - be. The actual midi note that gets played will be - this value + (12 * the current base octave). To change - the base octave, see setKeyPressBaseOctave() - */ - void setKeyPressForNote (const KeyPress& key, - const int midiNoteOffsetFromC); + void saveState(); + void restoreState(); - /** Removes any key-mappings for a given note. + bool clipRegionIntersects (const Rectangle& r); + const Rectangle getClipBounds() const; + bool isClipEmpty() const; - For a description of what the note number means, see setKeyPressForNote(). - */ - void removeKeyPressForNote (const int midiNoteOffsetFromC); + void setFill (const FillType& fillType); + void setOpacity (float opacity); + void setInterpolationQuality (Graphics::ResamplingQuality quality); - /** Changes the base note above which key-press-triggered notes are played. + void fillRect (const Rectangle& r, const bool replaceExistingContents); + void fillPath (const Path& path, const AffineTransform& transform); - The set of key-mappings that trigger notes can be moved up and down to cover - the entire scale using this method. + void drawImage (const Image& sourceImage, const Rectangle& srcClip, + const AffineTransform& transform, const bool fillEntireClipAsTiles); - The value passed in is an octave number between 0 and 10 (inclusive), and - indicates which C is the base note to which the key-mapped notes are - relative. - */ - void setKeyPressBaseOctave (const int newOctaveNumber); + void drawLine (double x1, double y1, double x2, double y2); - /** This sets the octave number which is shown as the octave number for middle C. + void drawVerticalLine (const int x, double top, double bottom); + void drawHorizontalLine (const int x, double top, double bottom); - This affects only the default implementation of getWhiteNoteText(), which - passes this octave number to MidiMessage::getMidiNoteName() in order to - get the note text. See MidiMessage::getMidiNoteName() for more info about - the parameter. + const Font getFont(); + void setFont (const Font& newFont); + void drawGlyph (int glyphNumber, const AffineTransform& transform); - By default this value is set to 3. + juce_UseDebuggingNewOperator - @see getOctaveForMiddleC - */ - void setOctaveForMiddleC (const int octaveNumForMiddleC) throw(); +protected: - /** This returns the value set by setOctaveForMiddleC(). - @see setOctaveForMiddleC - */ - int getOctaveForMiddleC() const throw() { return octaveNumForMiddleC; } + OutputStream& out; + int totalWidth, totalHeight; + bool needToClip; + Colour lastColour; - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void mouseMove (const MouseEvent& e); - /** @internal */ - void mouseDrag (const MouseEvent& e); - /** @internal */ - void mouseDown (const MouseEvent& e); - /** @internal */ - void mouseUp (const MouseEvent& e); - /** @internal */ - void mouseEnter (const MouseEvent& e); - /** @internal */ - void mouseExit (const MouseEvent& e); - /** @internal */ - void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); - /** @internal */ - void timerCallback(); - /** @internal */ - bool keyStateChanged (const bool isKeyDown); - /** @internal */ - void focusLost (FocusChangeType cause); - /** @internal */ - void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity); - /** @internal */ - void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber); - /** @internal */ - void handleAsyncUpdate(); - /** @internal */ - void colourChanged(); + struct SavedState + { + SavedState(); + ~SavedState(); - juce_UseDebuggingNewOperator + RectangleList clip; + int xOffset, yOffset; + FillType fillType; + Font font; -protected: - friend class MidiKeyboardUpDownButton; + private: + const SavedState& operator= (const SavedState&); + }; - /** Draws a white note in the given rectangle. + OwnedArray stateStack; - isOver indicates whether the mouse is over the key, isDown indicates whether the key is - currently pressed down. + void writeClip(); + void writeColour (const Colour& colour); + void writePath (const Path& path) const; + void writeXY (const float x, const float y) const; + void writeTransform (const AffineTransform& trans) const; + void writeImage (const Image& im, const int sx, const int sy, const int maxW, const int maxH) const; - When doing this, be sure to note the keyboard's orientation. - */ - virtual void drawWhiteNote (int midiNoteNumber, - Graphics& g, - int x, int y, int w, int h, - bool isDown, bool isOver, - const Colour& lineColour, - const Colour& textColour); + LowLevelGraphicsPostScriptRenderer (const LowLevelGraphicsPostScriptRenderer& other); + const LowLevelGraphicsPostScriptRenderer& operator= (const LowLevelGraphicsPostScriptRenderer&); +}; - /** Draws a black note in the given rectangle. +#endif // __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ +/********* End of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h *********/ - isOver indicates whether the mouse is over the key, isDown indicates whether the key is - currently pressed down. +#endif +#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ - When doing this, be sure to note the keyboard's orientation. - */ - virtual void drawBlackNote (int midiNoteNumber, - Graphics& g, - int x, int y, int w, int h, - bool isDown, bool isOver, - const Colour& noteFillColour); +/********* Start of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h *********/ +#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ +#define __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ - /** Allows text to be drawn on the white notes. +class LLGCSavedState; - By default this is used to label the C in each octave, but could be used for other things. +/** + A lowest-common-denominator implementation of LowLevelGraphicsContext that does all + its rendering in memory. - @see setOctaveForMiddleC - */ - virtual const String getWhiteNoteText (const int midiNoteNumber); + User code is not supposed to create instances of this class directly - do all your + rendering via the Graphics class instead. +*/ +class JUCE_API LowLevelGraphicsSoftwareRenderer : public LowLevelGraphicsContext +{ +public: - /** Draws the up and down buttons that change the base note. */ - virtual void drawUpDownButton (Graphics& g, int w, int h, - const bool isMouseOver, - const bool isButtonPressed, - const bool movesOctavesUp); + LowLevelGraphicsSoftwareRenderer (Image& imageToRenderOn); + ~LowLevelGraphicsSoftwareRenderer(); - /** Callback when the mouse is clicked on a key. + bool isVectorDevice() const; - You could use this to do things like handle right-clicks on keys, etc. + void setOrigin (int x, int y); - Return true if you want the click to trigger the note, or false if you - want to handle it yourself and not have the note played. + bool clipToRectangle (const Rectangle& r); + bool clipToRectangleList (const RectangleList& clipRegion); + void excludeClipRectangle (const Rectangle& r); + void clipToPath (const Path& path, const AffineTransform& transform); + void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); - @see mouseDraggedToKey - */ - virtual bool mouseDownOnKey (int midiNoteNumber, const MouseEvent& e); + bool clipRegionIntersects (const Rectangle& r); + const Rectangle getClipBounds() const; + bool isClipEmpty() const; - /** Callback when the mouse is dragged from one key onto another. + void saveState(); + void restoreState(); - @see mouseDownOnKey - */ - virtual void mouseDraggedToKey (int midiNoteNumber, const MouseEvent& e); + void setFill (const FillType& fillType); + void setOpacity (float opacity); + void setInterpolationQuality (Graphics::ResamplingQuality quality); - /** Calculates the positon of a given midi-note. + void fillRect (const Rectangle& r, const bool replaceExistingContents); + void fillPath (const Path& path, const AffineTransform& transform); - This can be overridden to create layouts with custom key-widths. + void drawImage (const Image& sourceImage, const Rectangle& srcClip, + const AffineTransform& transform, const bool fillEntireClipAsTiles); - @param midiNoteNumber the note to find - @param keyWidth the desired width in pixels of one key - see setKeyWidth() - @param x the x position of the left-hand edge of the key (this method - always works in terms of a horizontal keyboard) - @param w the width of the key - */ - virtual void getKeyPosition (int midiNoteNumber, float keyWidth, - int& x, int& w) const; + void drawLine (double x1, double y1, double x2, double y2); -private: + void drawVerticalLine (const int x, double top, double bottom); + void drawHorizontalLine (const int x, double top, double bottom); - MidiKeyboardState& state; - int xOffset, blackNoteLength; - float keyWidth; - Orientation orientation; + void setFont (const Font& newFont); + const Font getFont(); + void drawGlyph (int glyphNumber, float x, float y); + void drawGlyph (int glyphNumber, const AffineTransform& transform); - int midiChannel, midiInChannelMask; - float velocity; - int noteUnderMouse, mouseDownNote; - BitArray keysPressed, keysCurrentlyDrawnDown; + juce_UseDebuggingNewOperator - int rangeStart, rangeEnd, firstKey; - bool canScroll, mouseDragging, useMousePositionForVelocity; - Button* scrollDown; - Button* scrollUp; +protected: - Array keyPresses; - Array keyPressNotes; - int keyMappingOctave; - int octaveNumForMiddleC; + Image& image; - void getKeyPos (int midiNoteNumber, int& x, int& w) const; - int xyToNote (int x, int y, float& mousePositionVelocity); - int remappedXYToNote (int x, int y, float& mousePositionVelocity) const; - void resetAnyKeysInUse(); - void updateNoteUnderMouse (int x, int y); - void repaintNote (const int midiNoteNumber); + LLGCSavedState* currentState; + OwnedArray stateStack; - MidiKeyboardComponent (const MidiKeyboardComponent&); - const MidiKeyboardComponent& operator= (const MidiKeyboardComponent&); + LowLevelGraphicsSoftwareRenderer (const LowLevelGraphicsSoftwareRenderer& other); + const LowLevelGraphicsSoftwareRenderer& operator= (const LowLevelGraphicsSoftwareRenderer&); }; -#endif // __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_MidiKeyboardComponent.h *********/ +#endif // __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ +/********* End of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h *********/ #endif -#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ -/********* Start of inlined file: juce_NSViewComponent.h *********/ -#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ -#define __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_DRAWABLE_JUCEHEADER__ -#if ! DOXYGEN - class NSViewComponentInternal; #endif +#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ -#if JUCE_MAC || DOXYGEN +/********* Start of inlined file: juce_DrawableComposite.h *********/ +#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ +#define __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ /** - A Mac-specific class that can create and embed an NSView inside itself. - - To use it, create one of these, put it in place and make sure it's visible in a - window, then use setView() to assign an NSView to it. The view will then be - moved and resized to follow the movements of this component. + A drawable object which acts as a container for a set of other Drawables. - Of course, since the view is a native object, it'll obliterate any - juce components that may overlap this component, but that's life. + @see Drawable */ -class JUCE_API NSViewComponent : public Component +class JUCE_API DrawableComposite : public Drawable { public: - /** Create an initially-empty container. */ - NSViewComponent(); + /** Creates a composite Drawable. + */ + DrawableComposite(); /** Destructor. */ - ~NSViewComponent(); - - /** Assigns an NSView to this peer. - - The view will be retained and released by this component for as long as - it is needed. To remove the current view, just call setView (0). + virtual ~DrawableComposite(); - Note: a void* is used here to avoid including the cocoa headers as - part of the juce.h, but the method expects an NSView*. - */ - void setView (void* nsView); + /** Adds a new sub-drawable to this one. - /** Returns the current NSView. + This passes in a Drawable pointer for this object to look after. To add a copy + of a drawable, use the form of this method that takes a Drawable reference instead. - Note: a void* is returned here to avoid including the cocoa headers as - a requirement of juce.h, so you should just cast the object to an NSView*. + @param drawable the object to add - this will be deleted automatically + when no longer needed, so the caller mustn't keep any + pointers to it. + @param transform the transform to apply to this drawable when it's being + drawn + @param index where to insert it in the list of drawables. 0 is the back, + -1 is the front, or any value from 0 and getNumDrawables() + can be used + @see removeDrawable */ - void* getView() const; - - /** @internal */ - void paint (Graphics& g); - - juce_UseDebuggingNewOperator - -private: - friend class NSViewComponentInternal; - NSViewComponentInternal* info; + void insertDrawable (Drawable* drawable, + const AffineTransform& transform = AffineTransform::identity, + const int index = -1); - NSViewComponent (const NSViewComponent&); - const NSViewComponent& operator= (const NSViewComponent&); -}; + /** Adds a new sub-drawable to this one. -#endif + This takes a copy of a Drawable and adds it to this object. To pass in a Drawable + for this object to look after, use the form of this method that takes a Drawable + pointer instead. -#endif // __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_NSViewComponent.h *********/ + @param drawable the object to add - an internal copy will be made of this object + @param transform the transform to apply to this drawable when it's being + drawn + @param index where to insert it in the list of drawables. 0 is the back, + -1 is the front, or any value from 0 and getNumDrawables() + can be used + @see removeDrawable + */ + void insertDrawable (const Drawable& drawable, + const AffineTransform& transform = AffineTransform::identity, + const int index = -1); -#endif -#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ + /** Deletes one of the Drawable objects. -/********* Start of inlined file: juce_OpenGLComponent.h *********/ -#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ -#define __JUCE_OPENGLCOMPONENT_JUCEHEADER__ + @param index the index of the drawable to delete, between 0 + and (getNumDrawables() - 1). + @param deleteDrawable if this is true, the drawable that is removed will also + be deleted. If false, it'll just be removed. + @see insertDrawable, getNumDrawables + */ + void removeDrawable (const int index, const bool deleteDrawable = true); -// this is used to disable OpenGL, and is defined in juce_Config.h -#if JUCE_OPENGL || DOXYGEN + /** Returns the number of drawables contained inside this one. -class OpenGLComponentWatcher; + @see getDrawable + */ + int getNumDrawables() const throw() { return drawables.size(); } -/** - Represents the various properties of an OpenGL bitmap format. + /** Returns one of the drawables that are contained in this one. - @see OpenGLComponent::setPixelFormat -*/ -class JUCE_API OpenGLPixelFormat -{ -public: + Each drawable also has a transform associated with it - you can use getDrawableTransform() + to find it. - /** Creates an OpenGLPixelFormat. + The pointer returned is managed by this object and will be deleted when no longer + needed, so be careful what you do with it. - The default constructor just initialises the object as a simple 8-bit - RGBA format. + @see getNumDrawables */ - OpenGLPixelFormat (const int bitsPerRGBComponent = 8, - const int alphaBits = 8, - const int depthBufferBits = 16, - const int stencilBufferBits = 0) throw(); - - int redBits; /**< The number of bits per pixel to use for the red channel. */ - int greenBits; /**< The number of bits per pixel to use for the green channel. */ - int blueBits; /**< The number of bits per pixel to use for the blue channel. */ - int alphaBits; /**< The number of bits per pixel to use for the alpha channel. */ - - int depthBufferBits; /**< The number of bits per pixel to use for a depth buffer. */ - int stencilBufferBits; /**< The number of bits per pixel to use for a stencil buffer. */ - - int accumulationBufferRedBits; /**< The number of bits per pixel to use for an accumulation buffer's red channel. */ - int accumulationBufferGreenBits; /**< The number of bits per pixel to use for an accumulation buffer's green channel. */ - int accumulationBufferBlueBits; /**< The number of bits per pixel to use for an accumulation buffer's blue channel. */ - int accumulationBufferAlphaBits; /**< The number of bits per pixel to use for an accumulation buffer's alpha channel. */ + Drawable* getDrawable (const int index) const throw() { return drawables [index]; } - uint8 fullSceneAntiAliasingNumSamples; /**< The number of samples to use in full-scene anti-aliasing (if available). */ + /** Returns the transform that applies to one of the drawables that are contained in this one. - /** Returns a list of all the pixel formats that can be used in this system. + The pointer returned is managed by this object and will be deleted when no longer + needed, so be careful what you do with it. - A reference component is needed in case there are multiple screens with different - capabilities - in which case, the one that the component is on will be used. + @see getNumDrawables */ - static void getAvailablePixelFormats (Component* component, - OwnedArray & results); + const AffineTransform* getDrawableTransform (const int index) const throw() { return transforms [index]; } - bool operator== (const OpenGLPixelFormat&) const throw(); + /** Brings one of the Drawables to the front. + + @param index the index of the drawable to move, between 0 + and (getNumDrawables() - 1). + @see insertDrawable, getNumDrawables + */ + void bringToFront (const int index); + + /** @internal */ + void render (const Drawable::RenderingContext& context) const; + /** @internal */ + void getBounds (float& x, float& y, float& width, float& height) const; + /** @internal */ + bool hitTest (float x, float y) const; + /** @internal */ + Drawable* createCopy() const; + /** @internal */ + ValueTree createValueTree() const throw(); + /** @internal */ + static DrawableComposite* createFromValueTree (const ValueTree& tree) throw(); juce_UseDebuggingNewOperator + +private: + OwnedArray drawables; + OwnedArray transforms; + + DrawableComposite (const DrawableComposite&); + const DrawableComposite& operator= (const DrawableComposite&); }; +#endif // __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ +/********* End of inlined file: juce_DrawableComposite.h *********/ + +#endif +#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ + +/********* Start of inlined file: juce_DrawableImage.h *********/ +#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ +#define __JUCE_DRAWABLEIMAGE_JUCEHEADER__ + /** - A base class for types of OpenGL context. + A drawable object which is a bitmap image. - An OpenGLComponent will supply its own context for drawing in its window. + @see Drawable */ -class JUCE_API OpenGLContext +class JUCE_API DrawableImage : public Drawable { public: + DrawableImage(); + /** Destructor. */ - virtual ~OpenGLContext(); + virtual ~DrawableImage(); - /** Makes this context the currently active one. */ - virtual bool makeActive() const throw() = 0; - /** If this context is currently active, it is disactivated. */ - virtual bool makeInactive() const throw() = 0; - /** Returns true if this context is currently active. */ - virtual bool isActive() const throw() = 0; + /** Sets the image that this drawable will render. - /** Swaps the buffers (if the context can do this). */ - virtual void swapBuffers() = 0; + An internal copy is made of the image passed-in. If you want to provide an + image that this object can take charge of without needing to create a copy, + use the other setImage() method. + */ + void setImage (const Image& imageToCopy); - /** Sets whether the context checks the vertical sync before swapping. + /** Sets the image that this drawable will render. - The value is the number of frames to allow between buffer-swapping. This is - fairly system-dependent, but 0 turns off syncing, 1 makes it swap on frame-boundaries, - and greater numbers indicate that it should swap less often. + An internal copy of this will not be made, so the caller mustn't delete + the image while it's still being used by this object. - Returns true if it sets the value successfully. - */ - virtual bool setSwapInterval (const int numFramesPerSwap) = 0; + A good way to use this is with the ImageCache - if you create an image + with ImageCache and pass it in here with releaseWhenNotNeeded = true, then + it'll be released neatly with its reference count being decreased. - /** Returns the current swap-sync interval. - See setSwapInterval() for info about the value returned. + @param imageToUse the image to render + @param releaseWhenNotNeeded if false, a simple pointer is kept to the image; if true, + then the image will be deleted when this object no longer + needs it - unless the image was created by the ImageCache, + in which case it will be released with ImageCache::release(). */ - virtual int getSwapInterval() const = 0; - - /** Returns the pixel format being used by this context. */ - virtual const OpenGLPixelFormat getPixelFormat() const = 0; + void setImage (Image* imageToUse, + const bool releaseWhenNotNeeded); - /** For windowed contexts, this moves the context within the bounds of - its parent window. - */ - virtual void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) = 0; + /** Returns the current image. */ + Image* getImage() const throw() { return image; } - /** For windowed contexts, this triggers a repaint of the window. + /** Clears (and possibly deletes) the currently set image. */ + void clearImage(); - (Not relevent on all platforms). - */ - virtual void repaint() = 0; + /** Sets the opacity to use when drawing the image. */ + void setOpacity (const float newOpacity); - /** Returns an OS-dependent handle to the raw GL context. + /** Returns the image's opacity. */ + float getOpacity() const throw() { return opacity; } - On win32, this will be a HGLRC; on the Mac, an AGLContext; on Linux, - a GLXContext. - */ - virtual void* getRawContext() const throw() = 0; + /** Sets a colour to draw over the image's alpha channel. - /** This tries to create a context that can be used for drawing into the - area occupied by the specified component. + By default this is transparent so isn't drawn, but if you set a non-transparent + colour here, then it will be overlaid on the image, using the image's alpha + channel as a mask. - Note that you probably shouldn't use this method directly unless you know what - you're doing - the OpenGLComponent calls this and manages the context for you. + This is handy for doing things like darkening or lightening an image by overlaying + it with semi-transparent black or white. */ - static OpenGLContext* createContextForWindow (Component* componentToDrawTo, - const OpenGLPixelFormat& pixelFormat, - const OpenGLContext* const contextToShareWith); + void setOverlayColour (const Colour& newOverlayColour); - /** Returns the context that's currently in active use by the calling thread. + /** Returns the overlay colour. */ + const Colour& getOverlayColour() const throw() { return overlayColour; } - Returns 0 if there isn't an active context. - */ - static OpenGLContext* getCurrentContext(); + /** @internal */ + void render (const Drawable::RenderingContext& context) const; + /** @internal */ + void getBounds (float& x, float& y, float& width, float& height) const; + /** @internal */ + bool hitTest (float x, float y) const; + /** @internal */ + Drawable* createCopy() const; + /** @internal */ + ValueTree createValueTree() const throw(); + /** @internal */ + static DrawableImage* createFromValueTree (const ValueTree& tree) throw(); juce_UseDebuggingNewOperator -protected: - OpenGLContext() throw(); +private: + Image* image; + bool canDeleteImage; + float opacity; + Colour overlayColour; + + DrawableImage (const DrawableImage&); + const DrawableImage& operator= (const DrawableImage&); }; -/** - A component that contains an OpenGL canvas. +#endif // __JUCE_DRAWABLEIMAGE_JUCEHEADER__ +/********* End of inlined file: juce_DrawableImage.h *********/ - Override this, add it to whatever component you want to, and use the renderOpenGL() - method to draw its contents. +#endif +#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ + +/********* Start of inlined file: juce_DrawablePath.h *********/ +#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ +#define __JUCE_DRAWABLEPATH_JUCEHEADER__ + +/** + A drawable object which renders a filled or outlined shape. + @see Drawable */ -class JUCE_API OpenGLComponent : public Component +class JUCE_API DrawablePath : public Drawable { public: - /** Creates an OpenGLComponent. + /** Creates a DrawablePath. */ - OpenGLComponent(); + DrawablePath(); /** Destructor. */ - ~OpenGLComponent(); + virtual ~DrawablePath(); - /** Changes the pixel format used by this component. + /** Changes the path that will be drawn. - @see OpenGLPixelFormat::getAvailablePixelFormats() + @see setFillColour, setStrokeType */ - void setPixelFormat (const OpenGLPixelFormat& formatToUse); + void setPath (const Path& newPath) throw(); - /** Returns the pixel format that this component is currently using. */ - const OpenGLPixelFormat getPixelFormat() const; + /** Returns the current path. */ + const Path& getPath() const throw() { return path; } - /** Specifies an OpenGL context which should be shared with the one that this - component is using. + /** Sets a fill type for the path. - This is an OpenGL feature that lets two contexts share their texture data. + This colour is used to fill the path - if you don't want the path to be + filled (e.g. if you're just drawing an outline), set this to a transparent + colour. - Note that this pointer is stored by the component, and when the component - needs to recreate its internal context for some reason, the same context - will be used again to share lists. So if you pass a context in here, - don't delete the context while this component is still using it! You can - call shareWith (0) to stop this component from sharing with it. + @see setPath, setStrokeFill */ - void shareWith (OpenGLContext* contextToShareListsWith); + void setFill (const FillType& newFill) throw(); - /** Returns the context that this component is sharing with. - @see shareWith + /** Returns the current fill type. + @see setFill */ - OpenGLContext* getShareContext() const throw() { return contextToShareListsWith; } - - /** Flips the openGL buffers over. */ - void swapBuffers(); - - /** This replaces the normal paint() callback - use it to draw your openGL stuff. + const FillType& getFill() const throw() { return mainFill; } - When this is called, makeCurrentContextActive() will already have been called - for you, so you just need to draw. + /** Sets the fill type with which the outline will be drawn. + @see setFill */ - virtual void renderOpenGL() = 0; - - /** This method is called when the component creates a new OpenGL context. - - A new context may be created when the component is first used, or when it - is moved to a different window, or when the window is hidden and re-shown, - etc. - - You can use this callback as an opportunity to set up things like textures - that your context needs. - - New contexts are created on-demand by the makeCurrentContextActive() method - so - if the context is deleted, e.g. by changing the pixel format or window, no context - will be created until the next call to makeCurrentContextActive(), which will - synchronously create one and call this method. This means that if you're using - a non-GUI thread for rendering, you can make sure this method is be called by - your renderer thread. + void setStrokeFill (const FillType& newStrokeFill) throw(); - When this callback happens, the context will already have been made current - using the makeCurrentContextActive() method, so there's no need to call it - again in your code. + /** Returns the current stroke fill. + @see setStrokeFill */ - virtual void newOpenGLContextCreated() = 0; - - /** Returns the context that will draw into this component. + const FillType& getStrokeFill() const throw() { return strokeFill; } - This may return 0 if the component is currently invisible or hasn't currently - got a context. The context object can be deleted and a new one created during - the lifetime of this component, and there may be times when it doesn't have one. + /** Changes the properties of the outline that will be drawn around the path. + If the stroke has 0 thickness, no stroke will be drawn. + @see setStrokeThickness, setStrokeColour + */ + void setStrokeType (const PathStrokeType& newStrokeType) throw(); - @see newOpenGLContextCreated() + /** Changes the stroke thickness. + This is a shortcut for calling setStrokeType. */ - OpenGLContext* getCurrentContext() const throw() { return context; } + void setStrokeThickness (const float newThickness) throw(); - /** Makes this component the current openGL context. + /** Returns the current outline style. */ + const PathStrokeType& getStrokeType() const throw() { return strokeType; } - You might want to use this in things like your resize() method, before calling - GL commands. + /** @internal */ + void render (const Drawable::RenderingContext& context) const; + /** @internal */ + void getBounds (float& x, float& y, float& width, float& height) const; + /** @internal */ + bool hitTest (float x, float y) const; + /** @internal */ + Drawable* createCopy() const; + /** @internal */ + ValueTree createValueTree() const throw(); + /** @internal */ + static DrawablePath* createFromValueTree (const ValueTree& tree) throw(); - If this returns false, then the context isn't active, so you should avoid - making any calls. + juce_UseDebuggingNewOperator - This call may actually create a context if one isn't currently initialised. If - it does this, it will also synchronously call the newOpenGLContextCreated() - method to let you initialise it as necessary. +private: + Path path, stroke; + FillType mainFill, strokeFill; + PathStrokeType strokeType; - @see OpenGLContext::makeActive - */ - bool makeCurrentContextActive(); + void updateOutline(); - /** Stops the current component being the active OpenGL context. + DrawablePath (const DrawablePath&); + const DrawablePath& operator= (const DrawablePath&); +}; - This is the opposite of makeCurrentContextActive() +#endif // __JUCE_DRAWABLEPATH_JUCEHEADER__ +/********* End of inlined file: juce_DrawablePath.h *********/ - @see OpenGLContext::makeInactive - */ - void makeCurrentContextInactive(); +#endif +#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ - /** Returns true if this component is the active openGL context for the - current thread. +/********* Start of inlined file: juce_DrawableText.h *********/ +#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ +#define __JUCE_DRAWABLETEXT_JUCEHEADER__ - @see OpenGLContext::isActive - */ - bool isActiveContext() const throw(); +/** + A drawable object which renders a line of text. - /** Calls the rendering callback, and swaps the buffers afterwards. + @see Drawable +*/ +class JUCE_API DrawableText : public Drawable +{ +public: - This is called automatically by paint() when the component needs to be rendered. + /** Creates a DrawableText object. */ + DrawableText(); - It can be overridden if you need to decouple the rendering from the paint callback - and render with a custom thread. + /** Destructor. */ + virtual ~DrawableText(); - Returns true if the operation succeeded. - */ - virtual bool renderAndSwapBuffers(); + /** Sets the block of text to render */ + void setText (const GlyphArrangement& newText); - /** This returns a critical section that can be used to lock the current context. + /** Sets a single line of text to render. - Because the context that is used by this component can change, e.g. when the - component is shown or hidden, then if you're rendering to it on a background - thread, this allows you to lock the context for the duration of your rendering - routine. + This is a convenient method of adding a single line - for + more complex text, use the setText() that takes a + GlyphArrangement instead. */ - CriticalSection& getContextLock() throw() { return contextLock; } + void setText (const String& newText, const Font& fontToUse); - /** @internal */ - void paint (Graphics& g); + /** Returns the text arrangement that was set with setText(). */ + const GlyphArrangement& getText() const throw() { return text; } - /** Returns the native handle of an embedded heavyweight window, if there is one. + /** Sets the colour of the text. */ + void setColour (const Colour& newColour); - E.g. On windows, this will return the HWND of the sub-window containing - the opengl context, on the mac it'll be the NSOpenGLView. - */ - void* getNativeWindowHandle() const; + /** Returns the current text colour. */ + const Colour& getColour() const throw() { return colour; } + + /** @internal */ + void render (const Drawable::RenderingContext& context) const; + /** @internal */ + void getBounds (float& x, float& y, float& width, float& height) const; + /** @internal */ + bool hitTest (float x, float y) const; + /** @internal */ + Drawable* createCopy() const; + /** @internal */ + ValueTree createValueTree() const throw(); + /** @internal */ + static DrawableText* createFromValueTree (const ValueTree& tree) throw(); juce_UseDebuggingNewOperator private: - friend class OpenGLComponentWatcher; - OpenGLComponentWatcher* componentWatcher; - - OpenGLContext* context; - OpenGLContext* contextToShareListsWith; - - CriticalSection contextLock; - OpenGLPixelFormat preferredPixelFormat; - bool needToUpdateViewport; - - void deleteContext(); - void updateContextPosition(); - void internalRepaint (int x, int y, int w, int h); + GlyphArrangement text; + Colour colour; - OpenGLComponent (const OpenGLComponent&); - const OpenGLComponent& operator= (const OpenGLComponent&); + DrawableText (const DrawableText&); + const DrawableText& operator= (const DrawableText&); }; +#endif // __JUCE_DRAWABLETEXT_JUCEHEADER__ +/********* End of inlined file: juce_DrawableText.h *********/ + #endif -#endif // __JUCE_OPENGLCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_OpenGLComponent.h *********/ +#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ #endif -#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ +#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ -/********* Start of inlined file: juce_PreferencesPanel.h *********/ -#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ -#define __JUCE_PREFERENCESPANEL_JUCEHEADER__ +/********* Start of inlined file: juce_GlowEffect.h *********/ +#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ +#define __JUCE_GLOWEFFECT_JUCEHEADER__ /** - A component with a set of buttons at the top for changing between pages of - preferences. - - This is just a handy way of writing a Mac-style preferences panel where you - have a row of buttons along the top for the different preference categories, - each button having an icon above its name. Clicking these will show an - appropriate prefs page below it. + A component effect that adds a coloured blur around the component's contents. - You can either put one of these inside your own component, or just use the - showInDialogBox() method to show it in a window and run it modally. + (This will only work on non-opaque components). - To use it, just add a set of named pages with the addSettingsPage() method, - and implement the createComponentForPage() method to create suitable components - for each of these pages. + @see Component::setComponentEffect, DropShadowEffect */ -class JUCE_API PreferencesPanel : public Component, - private ButtonListener +class JUCE_API GlowEffect : public ImageEffectFilter { public: - /** Creates an empty panel. + /** Creates a default 'glow' effect. - Use addSettingsPage() to add some pages to it in your constructor. + To customise its appearance, use the setGlowProperties() method. */ - PreferencesPanel(); + GlowEffect(); /** Destructor. */ - ~PreferencesPanel(); - - /** Creates a page using a set of drawables to define the page's icon. + ~GlowEffect(); - Note that the other version of this method is much easier if you're using - an image instead of a custom drawable. + /** Sets the glow's radius and colour. - @param pageTitle the name of this preferences page - you'll need to - make sure your createComponentForPage() method creates - a suitable component when it is passed this name - @param normalIcon the drawable to display in the page's button normally - @param overIcon the drawable to display in the page's button when the mouse is over - @param downIcon the drawable to display in the page's button when the button is down - @see DrawableButton + The radius is how large the blur should be, and the colour is + used to render it (for a less intense glow, lower the colour's + opacity). */ - void addSettingsPage (const String& pageTitle, - const Drawable* normalIcon, - const Drawable* overIcon, - const Drawable* downIcon); + void setGlowProperties (const float newRadius, + const Colour& newColour); - /** Creates a page using a set of drawables to define the page's icon. + /** @internal */ + void applyEffect (Image& sourceImage, Graphics& destContext); - The other version of this method gives you more control over the icon, but this - one is much easier if you're just loading it from a file. + juce_UseDebuggingNewOperator - @param pageTitle the name of this preferences page - you'll need to - make sure your createComponentForPage() method creates - a suitable component when it is passed this name - @param imageData a block of data containing an image file, e.g. a jpeg, png or gif. - For this to look good, you'll probably want to use a nice - transparent png file. - @param imageDataSize the size of the image data, in bytes - */ - void addSettingsPage (const String& pageTitle, - const char* imageData, - const int imageDataSize); +private: + float radius; + Colour colour; +}; - /** Utility method to display this panel in a DialogWindow. +#endif // __JUCE_GLOWEFFECT_JUCEHEADER__ +/********* End of inlined file: juce_GlowEffect.h *********/ - Calling this will create a DialogWindow containing this panel with the - given size and title, and will run it modally, returning when the user - closes the dialog box. - */ - void showInDialogBox (const String& dialogtitle, - int dialogWidth, - int dialogHeight, - const Colour& backgroundColour = Colours::white); +#endif +#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ + +#endif +#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ + +/********* Start of inlined file: juce_ReduceOpacityEffect.h *********/ +#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ +#define __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ + +/** + An effect filter that reduces the image's opacity. + + This can be used to make a component (and its child components) more + transparent. + + @see Component::setComponentEffect +*/ +class JUCE_API ReduceOpacityEffect : public ImageEffectFilter +{ +public: + + /** Creates the effect object. + + The opacity of the component to which the effect is applied will be + scaled by the given factor (in the range 0 to 1.0f). + */ + ReduceOpacityEffect (const float opacity = 1.0f); - /** Subclasses must override this to return a component for each preferences page. + /** Destructor. */ + ~ReduceOpacityEffect(); - The subclass should return a pointer to a new component representing the named - page, which the panel will then display. + /** Sets how much to scale the component's opacity. - The panel will delete the component later when the user goes to another page - or deletes the panel. + @param newOpacity should be between 0 and 1.0f */ - virtual Component* createComponentForPage (const String& pageName) = 0; - - /** Changes the current page being displayed. */ - void setCurrentPage (const String& pageName); + void setOpacity (const float newOpacity); /** @internal */ - void resized(); - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void buttonClicked (Button* button); + void applyEffect (Image& sourceImage, Graphics& destContext); juce_UseDebuggingNewOperator private: + float opacity; +}; - String currentPageName; - Component* currentPage; - int buttonSize; +#endif // __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ +/********* End of inlined file: juce_ReduceOpacityEffect.h *********/ - PreferencesPanel (const PreferencesPanel&); - const PreferencesPanel& operator= (const PreferencesPanel&); -}; +#endif +#ifndef __JUCE_FONT_JUCEHEADER__ -#endif // __JUCE_PREFERENCESPANEL_JUCEHEADER__ -/********* End of inlined file: juce_PreferencesPanel.h *********/ +#endif +#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ #endif -#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ -/********* Start of inlined file: juce_WebBrowserComponent.h *********/ -#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ -#define __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_TYPEFACE_JUCEHEADER__ -#if JUCE_WEB_BROWSER || DOXYGEN +#endif +#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ + +#endif +#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ + +#endif +#ifndef __JUCE_LINE_JUCEHEADER__ -#if ! DOXYGEN - class WebBrowserComponentInternal; #endif +#ifndef __JUCE_PATH_JUCEHEADER__ + +#endif +#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ + +/********* Start of inlined file: juce_PathIterator.h *********/ +#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ +#define __JUCE_PATHITERATOR_JUCEHEADER__ /** - A component that displays an embedded web browser. + Flattens a Path object into a series of straight-line sections. - The browser itself will be platform-dependent. On the Mac, probably Safari, on - Windows, probably IE. + Use one of these to iterate through a Path object, and it will convert + all the curves into line sections so it's easy to render or perform + geometric operations on. + @see Path */ -class JUCE_API WebBrowserComponent : public Component +class JUCE_API PathFlatteningIterator { public: - /** Creates a WebBrowserComponent. + /** Creates a PathFlatteningIterator. - Once it's created and visible, send the browser to a URL using goToURL(). + After creation, use the next() method to initialise the fields in the + object with the first line's position. - @param unloadPageWhenBrowserIsHidden if this is true, then when the browser - component is taken offscreen, it'll clear the current page - and replace it with a blank page - this can be handy to stop - the browser using resources in the background when it's not - actually being used. + @param path the path to iterate along + @param transform a transform to apply to each point in the path being iterated + @param tolerence the amount by which the curves are allowed to deviate from the + lines into which they are being broken down - a higher tolerence + is a bit faster, but less smooth. */ - WebBrowserComponent (const bool unloadPageWhenBrowserIsHidden = true); + PathFlatteningIterator (const Path& path, + const AffineTransform& transform = AffineTransform::identity, + float tolerence = 6.0f) throw(); /** Destructor. */ - ~WebBrowserComponent(); + ~PathFlatteningIterator() throw(); - /** Sends the browser to a particular URL. + /** Fetches the next line segment from the path. - @param url the URL to go to. - @param headers an optional set of parameters to put in the HTTP header. If - you supply this, it should be a set of string in the form - "HeaderKey: HeaderValue" - @param postData an optional block of data that will be attached to the HTTP - POST request - */ - void goToURL (const String& url, - const StringArray* headers = 0, - const MemoryBlock* postData = 0); + This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath + so that they describe the new line segment. - /** Stops the current page loading. + @returns false when there are no more lines to fetch. */ - void stop(); + bool next() throw(); - /** Sends the browser back one page. - */ - void goBack(); + /** The x position of the start of the current line segment. */ + float x1; + /** The y position of the start of the current line segment. */ + float y1; + /** The x position of the end of the current line segment. */ + float x2; + /** The y position of the end of the current line segment. */ + float y2; - /** Sends the browser forward one page. - */ - void goForward(); + /** Indicates whether the current line segment is closing a sub-path. - /** Refreshes the browser. + If the current line is the one that connects the end of a sub-path + back to the start again, this will be true. */ - void refresh(); + bool closesSubPath; - /** This callback is called when the browser is about to navigate - to a new location. + /** The index of the current line within the current sub-path. - You can override this method to perform some action when the user - tries to go to a particular URL. To allow the operation to carry on, - return true, or return false to stop the navigation happening. + E.g. you can use this to see whether the line is the first one in the + subpath by seeing if it's 0. */ - virtual bool pageAboutToLoad (const String& newURL); + int subPathIndex; - /** @internal */ - void paint (Graphics& g); - /** @internal */ - void resized(); - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - void visibilityChanged(); + /** Returns true if the current segment is the last in the current sub-path. */ + bool isLastInSubpath() const throw() { return stackPos == stackBase + && (index >= path.numElements + || points [index] == Path::moveMarker); } juce_UseDebuggingNewOperator private: - WebBrowserComponentInternal* browser; - bool blankPageShown, unloadPageWhenBrowserIsHidden; - String lastURL; - StringArray lastHeaders; - MemoryBlock lastPostData; + const Path& path; + const AffineTransform transform; + float* points; + float tolerence, subPathCloseX, subPathCloseY; + bool isIdentityTransform; - void reloadLastURL(); - void checkWindowAssociation(); + HeapBlock stackBase; + float* stackPos; + int index, stackSize; - WebBrowserComponent (const WebBrowserComponent&); - const WebBrowserComponent& operator= (const WebBrowserComponent&); + PathFlatteningIterator (const PathFlatteningIterator&); + const PathFlatteningIterator& operator= (const PathFlatteningIterator&); }; +#endif // __JUCE_PATHITERATOR_JUCEHEADER__ +/********* End of inlined file: juce_PathIterator.h *********/ + #endif -#endif // __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_WebBrowserComponent.h *********/ +#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ #endif -#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ +#ifndef __JUCE_POINT_JUCEHEADER__ -/********* Start of inlined file: juce_SystemTrayIconComponent.h *********/ -#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ -#define __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ +#endif +#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ -#if JUCE_WINDOWS || JUCE_LINUX || DOXYGEN +/********* Start of inlined file: juce_PositionedRectangle.h *********/ +#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ +#define __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ /** - On Windows only, this component sits in the taskbar tray as a small icon. + A rectangle whose co-ordinates can be defined in terms of absolute or + proportional distances. - To use it, just create one of these components, but don't attempt to make it - visible, add it to a parent, or put it on the desktop. + Designed mainly for storing component positions, this gives you a lot of + control over how each co-ordinate is stored, either as an absolute position, + or as a proportion of the size of a parent rectangle. - You can then call setIconImage() to create an icon for it in the taskbar. + It also allows you to define the anchor points by which the rectangle is + positioned, so for example you could specify that the top right of the + rectangle should be an absolute distance from its parent's bottom-right corner. - To change the icon's tooltip, you can use setIconTooltip(). + This object can be stored as a string, which takes the form "x y w h", including + symbols like '%' and letters to indicate the anchor point. See its toString() + method for more info. - To respond to mouse-events, you can override the normal mouseDown(), - mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y - position will not be valid, you can use this to respond to clicks. Traditionally - you'd use a left-click to show your application's window, and a right-click - to show a pop-up menu. + Example usage: + @code + class MyComponent + { + void resized() + { + // this will set the child component's x to be 20% of our width, its y + // to be 30, its width to be 150, and its height to be 50% of our + // height.. + const PositionedRectangle pos1 ("20% 30 150 50%"); + pos1.applyToComponent (*myChildComponent1); + + // this will inset the child component with a gap of 10 pixels + // around each of its edges.. + const PositionedRectangle pos2 ("10 10 20M 20M"); + pos2.applyToComponent (*myChildComponent2); + } + }; + @endcode */ -class JUCE_API SystemTrayIconComponent : public Component +class JUCE_API PositionedRectangle { public: - SystemTrayIconComponent(); - - /** Destructor. */ - ~SystemTrayIconComponent(); + /** Creates an empty rectangle with all co-ordinates set to zero. - /** Changes the image shown in the taskbar. + The default anchor point is top-left; the default */ - void setIconImage (const Image& newImage); + PositionedRectangle() throw(); - /** Changes the tooltip that Windows shows above the icon. */ - void setIconTooltip (const String& tooltip); + /** Initialises a PositionedRectangle from a saved string version. -#if JUCE_LINUX - /** @internal */ - void paint (Graphics& g); -#endif + The string must be in the format generated by toString(). + */ + PositionedRectangle (const String& stringVersion) throw(); - juce_UseDebuggingNewOperator + /** Creates a copy of another PositionedRectangle. */ + PositionedRectangle (const PositionedRectangle& other) throw(); -private: + /** Copies another PositionedRectangle. */ + const PositionedRectangle& operator= (const PositionedRectangle& other) throw(); - SystemTrayIconComponent (const SystemTrayIconComponent&); - const SystemTrayIconComponent& operator= (const SystemTrayIconComponent&); -}; + /** Destructor. */ + ~PositionedRectangle() throw(); -#endif -#endif // __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_SystemTrayIconComponent.h *********/ + /** Returns a string version of this position, from which it can later be + re-generated. -#endif -#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ + The format is four co-ordinates, "x y w h". -/********* Start of inlined file: juce_QuickTimeMovieComponent.h *********/ -#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ -#define __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ + - If a co-ordinate is absolute, it is stored as an integer, e.g. "100". + - If a co-ordinate is proportional to its parent's width or height, it is stored + as a percentage, e.g. "80%". + - If the X or Y co-ordinate is relative to the parent's right or bottom edge, the + number has "R" appended to it, e.g. "100R" means a distance of 100 pixels from + the parent's right-hand edge. + - If the X or Y co-ordinate is relative to the parent's centre, the number has "C" + appended to it, e.g. "-50C" would be 50 pixels left of the parent's centre. + - If the X or Y co-ordinate should be anchored at the component's right or bottom + edge, then it has "r" appended to it. So "-50Rr" would mean that this component's + right-hand edge should be 50 pixels left of the parent's right-hand edge. + - If the X or Y co-ordinate should be anchored at the component's centre, then it + has "c" appended to it. So "-50Rc" would mean that this component's + centre should be 50 pixels left of the parent's right-hand edge. "40%c" means that + this component's centre should be placed 40% across the parent's width. + - If it's a width or height that should use the parentSizeMinusAbsolute mode, then + the number has "M" appended to it. -// (NB: This stuff mustn't go inside the "#if QUICKTIME" block, or it'll break the -// amalgamated build) -#if JUCE_WINDOWS + To reload a stored string, use the constructor that takes a string parameter. + */ + const String toString() const throw(); - typedef ActiveXControlComponent QTCompBaseClass; -#elif JUCE_MAC + /** Calculates the absolute position, given the size of the space that + it should go in. - typedef NSViewComponent QTCompBaseClass; -#endif + This will work out any proportional distances and sizes relative to the + target rectangle, and will return the absolute position. -// this is used to disable QuickTime, and is defined in juce_Config.h -#if JUCE_QUICKTIME || DOXYGEN + @see applyToComponent + */ + const Rectangle getRectangle (const Rectangle& targetSpaceToBeRelativeTo) const throw(); -/** - A window that can play back a QuickTime movie. + /** Same as getRectangle(), but returning the values as doubles rather than ints. + */ + void getRectangleDouble (const Rectangle& targetSpaceToBeRelativeTo, + double& x, + double& y, + double& width, + double& height) const throw(); -*/ -class JUCE_API QuickTimeMovieComponent : public QTCompBaseClass -{ -public: + /** This sets the bounds of the given component to this position. - /** Creates a QuickTimeMovieComponent, initially blank. + This is equivalent to writing: + @code + comp.setBounds (getRectangle (Rectangle (0, 0, comp.getParentWidth(), comp.getParentHeight()))); + @endcode - Use the loadMovie() method to load a movie once you've added the - component to a window, (or put it on the desktop as a heavyweight window). - Loading a movie when the component isn't visible can cause problems, as - QuickTime needs a window handle to initialise properly. + @see getRectangle, updateFromComponent */ - QuickTimeMovieComponent(); + void applyToComponent (Component& comp) const throw(); - /** Destructor. */ - ~QuickTimeMovieComponent(); + /** Updates this object's co-ordinates to match the given rectangle. - /** Returns true if QT is installed and working on this machine. - */ - static bool isQuickTimeAvailable() throw(); + This will set all co-ordinates based on the given rectangle, re-calculating + any proportional distances, and using the current anchor points. - /** Tries to load a QuickTime movie from a file into the player. + So for example if the x co-ordinate mode is currently proportional, this will + re-calculate x based on the rectangle's relative position within the target + rectangle's width. - It's best to call this function once you've added the component to a window, - (or put it on the desktop as a heavyweight window). Loading a movie when the - component isn't visible can cause problems, because QuickTime needs a window - handle to do its stuff. + If the target rectangle's width or height are zero then it may not be possible + to re-calculate some proportional co-ordinates. In this case, those co-ordinates + will not be changed. + */ + void updateFrom (const Rectangle& newPosition, + const Rectangle& targetSpaceToBeRelativeTo) throw(); - @param movieFile the .mov file to open - @param isControllerVisible whether to show a controller bar at the bottom - @returns true if the movie opens successfully + /** Same functionality as updateFrom(), but taking doubles instead of ints. */ - bool loadMovie (const File& movieFile, - const bool isControllerVisible); + void updateFromDouble (const double x, const double y, + const double width, const double height, + const Rectangle& targetSpaceToBeRelativeTo) throw(); - /** Tries to load a QuickTime movie from a URL into the player. + /** Updates this object's co-ordinates to match the bounds of this component. - It's best to call this function once you've added the component to a window, - (or put it on the desktop as a heavyweight window). Loading a movie when the - component isn't visible can cause problems, because QuickTime needs a window - handle to do its stuff. + This is equivalent to calling updateFrom() with the component's bounds and + it parent size. - @param movieURL the .mov file to open - @param isControllerVisible whether to show a controller bar at the bottom - @returns true if the movie opens successfully + If the component doesn't currently have a parent, then proportional co-ordinates + might not be updated because it would need to know the parent's size to do the + maths for this. */ - bool loadMovie (const URL& movieURL, - const bool isControllerVisible); - - /** Tries to load a QuickTime movie from a stream into the player. + void updateFromComponent (const Component& comp) throw(); - It's best to call this function once you've added the component to a window, - (or put it on the desktop as a heavyweight window). Loading a movie when the - component isn't visible can cause problems, because QuickTime needs a window - handle to do its stuff. + /** Specifies the point within the rectangle, relative to which it should be positioned. */ + enum AnchorPoint + { + anchorAtLeftOrTop = 1 << 0, /**< The x or y co-ordinate specifies where the left or top edge of the rectangle should be. */ + anchorAtRightOrBottom = 1 << 1, /**< The x or y co-ordinate specifies where the right or bottom edge of the rectangle should be. */ + anchorAtCentre = 1 << 2 /**< The x or y co-ordinate specifies where the centre of the rectangle should be. */ + }; - @param movieStream a stream containing a .mov file. The component may try - to read the whole stream before playing, rather than - streaming from it. - @param isControllerVisible whether to show a controller bar at the bottom - @returns true if the movie opens successfully - */ - bool loadMovie (InputStream* movieStream, - const bool isControllerVisible); + /** Specifies how an x or y co-ordinate should be interpreted. */ + enum PositionMode + { + absoluteFromParentTopLeft = 1 << 3, /**< The x or y co-ordinate specifies an absolute distance from the parent's top or left edge. */ + absoluteFromParentBottomRight = 1 << 4, /**< The x or y co-ordinate specifies an absolute distance from the parent's bottom or right edge. */ + absoluteFromParentCentre = 1 << 5, /**< The x or y co-ordinate specifies an absolute distance from the parent's centre. */ + proportionOfParentSize = 1 << 6 /**< The x or y co-ordinate specifies a proportion of the parent's width or height, measured from the parent's top or left. */ + }; - /** Closes the movie, if one is open. */ - void closeMovie(); + /** Specifies how the width or height should be interpreted. */ + enum SizeMode + { + absoluteSize = 1 << 0, /**< The width or height specifies an absolute size. */ + parentSizeMinusAbsolute = 1 << 1, /**< The width or height is an amount that should be subtracted from the parent's width or height. */ + proportionalSize = 1 << 2, /**< The width or height specifies a proportion of the parent's width or height. */ + }; - /** Returns the movie file that is currently open. + /** Sets all options for all co-ordinates. - If there isn't one, this returns File::nonexistent + This requires a reference rectangle to be specified, because if you're changing any + of the modes from proportional to absolute or vice-versa, then it'll need to convert + the co-ordinates, and will need to know the parent size so it can calculate this. */ - const File getCurrentMovieFile() const; - - /** Returns true if there's currently a movie open. */ - bool isMovieOpen() const; + void setModes (const AnchorPoint xAnchorMode, + const PositionMode xPositionMode, + const AnchorPoint yAnchorMode, + const PositionMode yPositionMode, + const SizeMode widthMode, + const SizeMode heightMode, + const Rectangle& targetSpaceToBeRelativeTo) throw(); - /** Returns the length of the movie, in seconds. */ - double getMovieDuration() const; + /** Returns the anchoring mode for the x co-ordinate. + To change any of the modes, use setModes(). + */ + AnchorPoint getAnchorPointX() const throw(); - /** Returns the movie's natural size, in pixels. + /** Returns the positioning mode for the x co-ordinate. + To change any of the modes, use setModes(). + */ + PositionMode getPositionModeX() const throw(); - You can use this to resize the component to show the movie at its preferred - scale. + /** Returns the raw x co-ordinate. - If no movie is loaded, the size returned will be 0 x 0. + If the x position mode is absolute, then this will be the absolute value. If it's + proportional, then this will be a fractional proportion, where 1.0 means the full + width of the parent space. */ - void getMovieNormalSize (int& width, int& height) const; + double getX() const throw() { return x; } - /** This will position the component within a given area, keeping its aspect - ratio correct according to the movie's normal size. + /** Sets the raw value of the x co-ordinate. - The component will be made as large as it can go within the space, and will - be aligned according to the justification value if this means there are gaps at - the top or sides. + See getX() for the meaning of this value. */ - void setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin, - const RectanglePlacement& placement); - - /** Starts the movie playing. */ - void play(); + void setX (const double newX) throw() { x = newX; } - /** Stops the movie playing. */ - void stop(); + /** Returns the anchoring mode for the y co-ordinate. + To change any of the modes, use setModes(). + */ + AnchorPoint getAnchorPointY() const throw(); - /** Returns true if the movie is currently playing. */ - bool isPlaying() const; + /** Returns the positioning mode for the y co-ordinate. + To change any of the modes, use setModes(). + */ + PositionMode getPositionModeY() const throw(); - /** Moves the movie's position back to the start. */ - void goToStart(); + /** Returns the raw y co-ordinate. - /** Sets the movie's position to a given time. */ - void setPosition (const double seconds); + If the y position mode is absolute, then this will be the absolute value. If it's + proportional, then this will be a fractional proportion, where 1.0 means the full + height of the parent space. + */ + double getY() const throw() { return y; } - /** Returns the current play position of the movie. */ - double getPosition() const; + /** Sets the raw value of the y co-ordinate. - /** Changes the movie playback rate. + See getY() for the meaning of this value. + */ + void setY (const double newY) throw() { y = newY; } - A value of 1 is normal speed, greater values play it proportionately faster, - smaller values play it slower. + /** Returns the mode used to calculate the width. + To change any of the modes, use setModes(). */ - void setSpeed (const float newSpeed); + SizeMode getWidthMode() const throw(); - /** Changes the movie's playback volume. + /** Returns the raw width value. - @param newVolume the volume in the range 0 (silent) to 1.0 (full) + If the width mode is absolute, then this will be the absolute value. If the mode is + proportional, then this will be a fractional proportion, where 1.0 means the full + width of the parent space. */ - void setMovieVolume (const float newVolume); + double getWidth() const throw() { return w; } - /** Returns the movie's playback volume. + /** Sets the raw width value. - @returns the volume in the range 0 (silent) to 1.0 (full) + See getWidth() for the details about what this value means. */ - float getMovieVolume() const; + void setWidth (const double newWidth) throw() { w = newWidth; } - /** Tells the movie whether it should loop. */ - void setLooping (const bool shouldLoop); + /** Returns the mode used to calculate the height. + To change any of the modes, use setModes(). + */ + SizeMode getHeightMode() const throw(); - /** Returns true if the movie is currently looping. + /** Returns the raw height value. - @see setLooping + If the height mode is absolute, then this will be the absolute value. If the mode is + proportional, then this will be a fractional proportion, where 1.0 means the full + height of the parent space. */ - bool isLooping() const; + double getHeight() const throw() { return h; } - /** True if the native QuickTime controller bar is shown in the window. + /** Sets the raw height value. - @see loadMovie + See getHeight() for the details about what this value means. */ - bool isControllerVisible() const; + void setHeight (const double newHeight) throw() { h = newHeight; } - /** @internal */ - void paint (Graphics& g); + /** If the size and position are constance, and wouldn't be affected by changes + in the parent's size, then this will return true. + */ + bool isPositionAbsolute() const throw(); + + /** Compares two objects. */ + const bool operator== (const PositionedRectangle& other) const throw(); + + /** Compares two objects. */ + const bool operator!= (const PositionedRectangle& other) const throw(); juce_UseDebuggingNewOperator private: - File movieFile; - bool movieLoaded, controllerVisible, looping; + double x, y, w, h; + uint8 xMode, yMode, wMode, hMode; -#if JUCE_WINDOWS - /** @internal */ - void parentHierarchyChanged(); - /** @internal */ - void visibilityChanged(); + void addPosDescription (String& result, const uint8 mode, const double value) const throw(); + void addSizeDescription (String& result, const uint8 mode, const double value) const throw(); + void decodePosString (const String& s, uint8& mode, double& value) throw(); + void decodeSizeString (const String& s, uint8& mode, double& value) throw(); + void applyPosAndSize (double& xOut, double& wOut, const double x, const double w, + const uint8 xMode, const uint8 wMode, + const int parentPos, const int parentSize) const throw(); + void updatePosAndSize (double& xOut, double& wOut, double x, const double w, + const uint8 xMode, const uint8 wMode, + const int parentPos, const int parentSize) const throw(); +}; - void createControlIfNeeded(); - bool isControlCreated() const; - void* internal; -#else - void* movie; -#endif +#endif // __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ +/********* End of inlined file: juce_PositionedRectangle.h *********/ - QuickTimeMovieComponent (const QuickTimeMovieComponent&); - const QuickTimeMovieComponent& operator= (const QuickTimeMovieComponent&); -}; +#endif +#ifndef __JUCE_RECTANGLE_JUCEHEADER__ #endif -#endif // __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ -/********* End of inlined file: juce_QuickTimeMovieComponent.h *********/ +#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ #endif -#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ +#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ -/********* Start of inlined file: juce_LookAndFeel.h *********/ -#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ -#define __JUCE_LOOKANDFEEL_JUCEHEADER__ +/********* Start of inlined file: juce_CameraDevice.h *********/ +#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ +#define __JUCE_CAMERADEVICE_JUCEHEADER__ -class ToggleButton; -class TextButton; -class AlertWindow; -class TextLayout; -class ScrollBar; -class BubbleComponent; -class ComboBox; -class Button; -class FilenameComponent; -class DocumentWindow; -class ResizableWindow; -class GroupComponent; -class MenuBarComponent; -class DropShadower; -class GlyphArrangement; -class PropertyComponent; -class TableHeaderComponent; -class Toolbar; -class ToolbarItemComponent; -class PopupMenu; -class ProgressBar; -class FileBrowserComponent; -class DirectoryContentsDisplayComponent; -class FilePreviewComponent; -class ImageButton; +#if JUCE_USE_CAMERA /** - LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses - can be used to apply different 'skins' to the application. + Receives callbacks with images from a CameraDevice. + @see CameraDevice::addListener */ -class JUCE_API LookAndFeel +class CameraImageListener { public: + CameraImageListener() {} + virtual ~CameraImageListener() {} - /** Creates the default JUCE look and feel. */ - LookAndFeel(); - - /** Destructor. */ - virtual ~LookAndFeel(); - - /** Returns the current default look-and-feel for a component to use when it - hasn't got one explicitly set. + /** This method is called when a new image arrives. - @see setDefaultLookAndFeel + This may be called by any thread, so be careful about thread-safety, + and make sure that you process the data as quickly as possible to + avoid glitching! */ - static LookAndFeel& getDefaultLookAndFeel() throw(); + virtual void imageReceived (Image& image) = 0; +}; - /** Changes the default look-and-feel. +/** + Controls any camera capture devices that might be available. - @param newDefaultLookAndFeel the new look-and-feel object to use - if this is - set to 0, it will revert to using the default one. The - object passed-in must be deleted by the caller when - it's no longer needed. - @see getDefaultLookAndFeel - */ - static void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) throw(); + Use getAvailableDevices() to list the devices that are attached to the + system, then call openDevice to open one for use. Once you have a CameraDevice + object, you can get a viewer component from it, and use its methods to + stream to a file or capture still-frames. +*/ +class JUCE_API CameraDevice +{ +public: + /** Destructor. */ + virtual ~CameraDevice(); - /** Looks for a colour that has been registered with the given colour ID number. + /** Returns a list of the available cameras on this machine. - If a colour has been set for this ID number using setColour(), then it is - returned. If none has been set, it will just return Colours::black. + You can open one of these devices by calling openDevice(). + */ + static const StringArray getAvailableDevices(); - The colour IDs for various purposes are stored as enums in the components that - they are relevent to - for an example, see Slider::ColourIds, - Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. + /** Opens a camera device. - If you're looking up a colour for use in drawing a component, it's usually - best not to call this directly, but to use the Component::findColour() method - instead. That will first check whether a suitable colour has been registered - directly with the component, and will fall-back on calling the component's - LookAndFeel's findColour() method if none is found. + The index parameter indicates which of the items returned by getAvailableDevices() + to open. - @see setColour, Component::findColour, Component::setColour + The size constraints allow the method to choose between different resolutions if + the camera supports this. If the resolution cam't be specified (e.g. on the Mac) + then these will be ignored. */ - const Colour findColour (const int colourId) const throw(); - - /** Registers a colour to be used for a particular purpose. + static CameraDevice* openDevice (int deviceIndex, + int minWidth = 128, int minHeight = 64, + int maxWidth = 1024, int maxHeight = 768); - For more details, see the comments for findColour(). + /** Returns the name of this device */ + const String getName() const throw() { return name; } - @see findColour, Component::findColour, Component::setColour + /** Creates a component that can be used to display a preview of the + video from this camera. */ - void setColour (const int colourId, const Colour& colour) throw(); + Component* createViewerComponent(); - /** Returns true if the specified colour ID has been explicitly set using the - setColour() method. - */ - bool isColourSpecified (const int colourId) const throw(); + /** Starts recording video to the specified file. - virtual const Typeface::Ptr getTypefaceForFont (const Font& font); + You should use getFileExtension() to find out the correct extension to + use for your filename. - /** Allows you to change the default sans-serif font. + If the file exists, it will be deleted before the recording starts. - If you need to supply your own Typeface object for any of the default fonts, rather - than just supplying the name (e.g. if you want to use an embedded font), then - you should instead override getTypefaceForFont() to create and return the typeface. + This method may not start recording instantly, so if you need to know the + exact time at which the file begins, you can call getTimeOfFirstRecordedFrame() + after the recording has finished. */ - void setDefaultSansSerifTypefaceName (const String& newName); + void startRecordingToFile (const File& file); - /** Override this to get the chance to swap a component's mouse cursor for a - customised one. + /** Stops recording, after a call to startRecordingToFile(). */ - virtual const MouseCursor getMouseCursorFor (Component& component); - - /** Draws the lozenge-shaped background for a standard button. */ - virtual void drawButtonBackground (Graphics& g, - Button& button, - const Colour& backgroundColour, - bool isMouseOverButton, - bool isButtonDown); - - virtual const Font getFontForTextButton (TextButton& button); + void stopRecording(); - /** Draws the text for a TextButton. */ - virtual void drawButtonText (Graphics& g, - TextButton& button, - bool isMouseOverButton, - bool isButtonDown); + /** Returns the file extension that should be used for the files + that you pass to startRecordingToFile(). - /** Draws the contents of a standard ToggleButton. */ - virtual void drawToggleButton (Graphics& g, - ToggleButton& button, - bool isMouseOverButton, - bool isButtonDown); + This may be platform-specific, e.g. ".mov" or ".avi". + */ + static const String getFileExtension(); - virtual void changeToggleButtonWidthToFitText (ToggleButton& button); + /** After calling stopRecording(), this method can be called to return the timestamp + of the first frame that was written to the file. + */ + const Time getTimeOfFirstRecordedFrame() const; - virtual void drawTickBox (Graphics& g, - Component& component, - int x, int y, int w, int h, - const bool ticked, - const bool isEnabled, - const bool isMouseOverButton, - const bool isButtonDown); + /** Adds a listener to receive images from the camera. - /* AlertWindow handling.. + Be very careful not to delete the listener without first removing it by calling + removeListener(). */ - virtual AlertWindow* createAlertWindow (const String& title, - const String& message, - const String& button1, - const String& button2, - const String& button3, - AlertWindow::AlertIconType iconType, - int numButtons, - Component* associatedComponent); + void addListener (CameraImageListener* listenerToAdd); - virtual void drawAlertBox (Graphics& g, - AlertWindow& alert, - const Rectangle& textArea, - TextLayout& textLayout); + /** Removes a listener that was previously added with addListener(). + */ + void removeListener (CameraImageListener* listenerToRemove); - virtual int getAlertBoxWindowFlags(); + juce_UseDebuggingNewOperator - virtual int getAlertWindowButtonHeight(); +protected: + /** @internal */ + CameraDevice (const String& name, int index); - virtual const Font getAlertWindowFont(); +private: + void* internal; + bool isRecording; + String name; - /** Draws a progress bar. + CameraDevice (const CameraDevice&); + const CameraDevice& operator= (const CameraDevice&); +}; - If the progress value is less than 0 or greater than 1.0, this should draw a spinning - bar that fills the whole space (i.e. to say that the app is still busy but the progress - isn't known). It can use the current time as a basis for playing an animation. +#endif +#endif // __JUCE_CAMERADEVICE_JUCEHEADER__ +/********* End of inlined file: juce_CameraDevice.h *********/ - (Used by progress bars in AlertWindow). - */ - virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar, - int width, int height, - double progress, const String& textToShow); +#endif +#ifndef __JUCE_IMAGE_JUCEHEADER__ - // Draws a small image that spins to indicate that something's happening.. - // This method should use the current time to animate itself, so just keep - // repainting it every so often. - virtual void drawSpinningWaitAnimation (Graphics& g, const Colour& colour, - int x, int y, int w, int h); +#endif +#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ - /** Draws one of the buttons on a scrollbar. +/********* Start of inlined file: juce_ImageCache.h *********/ +#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ +#define __JUCE_IMAGECACHE_JUCEHEADER__ - @param g the context to draw into - @param scrollbar the bar itself - @param width the width of the button - @param height the height of the button - @param buttonDirection the direction of the button, where 0 = up, 1 = right, 2 = down, 3 = left - @param isScrollbarVertical true if it's a vertical bar, false if horizontal - @param isMouseOverButton whether the mouse is currently over the button (also true if it's held down) - @param isButtonDown whether the mouse button's held down - */ - virtual void drawScrollbarButton (Graphics& g, - ScrollBar& scrollbar, - int width, int height, - int buttonDirection, - bool isScrollbarVertical, - bool isMouseOverButton, - bool isButtonDown); +/** + A global cache of images that have been loaded from files or memory. - /** Draws the thumb area of a scrollbar. + If you're loading an image and may need to use the image in more than one + place, this is used to allow the same image to be shared rather than loading + multiple copies into memory. - @param g the context to draw into - @param scrollbar the bar itself - @param x the x position of the left edge of the thumb area to draw in - @param y the y position of the top edge of the thumb area to draw in - @param width the width of the thumb area to draw in - @param height the height of the thumb area to draw in - @param isScrollbarVertical true if it's a vertical bar, false if horizontal - @param thumbStartPosition for vertical bars, the y co-ordinate of the top of the - thumb, or its x position for horizontal bars - @param thumbSize for vertical bars, the height of the thumb, or its width for - horizontal bars. This may be 0 if the thumb shouldn't be drawn. - @param isMouseOver whether the mouse is over the thumb area, also true if the mouse is - currently dragging the thumb - @param isMouseDown whether the mouse is currently dragging the scrollbar - */ - virtual void drawScrollbar (Graphics& g, - ScrollBar& scrollbar, - int x, int y, - int width, int height, - bool isScrollbarVertical, - int thumbStartPosition, - int thumbSize, - bool isMouseOver, - bool isMouseDown); + Another advantage is that after images are released, they will be kept in + memory for a few seconds before it is actually deleted, so if you're repeatedly + loading/deleting the same image, it'll reduce the chances of having to reload it + each time. - /** Returns the component effect to use for a scrollbar */ - virtual ImageEffectFilter* getScrollbarEffect(); + @see Image, ImageFileFormat +*/ +class JUCE_API ImageCache : private DeletedAtShutdown, + private Timer +{ +public: - /** Returns the minimum length in pixels to use for a scrollbar thumb. */ - virtual int getMinimumScrollbarThumbSize (ScrollBar& scrollbar); + /** Loads an image from a file, (or just returns the image if it's already cached). - /** Returns the default thickness to use for a scrollbar. */ - virtual int getDefaultScrollbarWidth(); + If the cache already contains an image that was loaded from this file, + that image will be returned. Otherwise, this method will try to load the + file, add it to the cache, and return it. - /** Returns the length in pixels to use for a scrollbar button. */ - virtual int getScrollbarButtonSize (ScrollBar& scrollbar); + It's very important not to delete the image that is returned - instead use + the ImageCache::release() method. - /** Returns a tick shape for use in yes/no boxes, etc. */ - virtual const Path getTickShape (const float height); - /** Returns a cross shape for use in yes/no boxes, etc. */ - virtual const Path getCrossShape (const float height); + Also, remember that the image returned is shared, so drawing into it might + affect other things that are using it! - /** Draws the + or - box in a treeview. */ - virtual void drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus, bool isMouseOver); + @param file the file to try to load + @returns the image, or null if it there was an error loading it + @see release, getFromMemory, getFromCache, ImageFileFormat::loadFrom + */ + static Image* getFromFile (const File& file); - virtual void fillTextEditorBackground (Graphics& g, int width, int height, TextEditor& textEditor); - virtual void drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor); + /** Loads an image from an in-memory image file, (or just returns the image if it's already cached). - // these return an image from the ImageCache, so use ImageCache::release() to free it - virtual Image* getDefaultFolderImage(); - virtual Image* getDefaultDocumentFileImage(); + If the cache already contains an image that was loaded from this block of memory, + that image will be returned. Otherwise, this method will try to load the + file, add it to the cache, and return it. - virtual void createFileChooserHeaderText (const String& title, - const String& instructions, - GlyphArrangement& destArrangement, - int width); + It's very important not to delete the image that is returned - instead use + the ImageCache::release() method. - virtual void drawFileBrowserRow (Graphics& g, int width, int height, - const String& filename, Image* icon, - const String& fileSizeDescription, - const String& fileTimeDescription, - const bool isDirectory, - const bool isItemSelected, - const int itemIndex); + Also, remember that the image returned is shared, so drawing into it might + affect other things that are using it! - virtual Button* createFileBrowserGoUpButton(); + @param imageData the block of memory containing the image data + @param dataSize the data size in bytes + @returns the image, or null if it there was an error loading it + @see release, getFromMemory, getFromCache, ImageFileFormat::loadFrom + */ + static Image* getFromMemory (const void* imageData, + const int dataSize); - virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp, - DirectoryContentsDisplayComponent* fileListComponent, - FilePreviewComponent* previewComp, - ComboBox* currentPathBox, - TextEditor* filenameBox, - Button* goUpButton); + /** Releases an image that was previously created by the ImageCache. - virtual void drawBubble (Graphics& g, - float tipX, float tipY, - float boxX, float boxY, float boxW, float boxH); + If an image has been returned by the getFromFile() or getFromMemory() methods, + it mustn't be deleted directly, but should be released with this method + instead. - /** Fills the background of a popup menu component. */ - virtual void drawPopupMenuBackground (Graphics& g, int width, int height); + @see getFromFile, getFromMemory + */ + static void release (Image* const imageToRelease); - /** Draws one of the items in a popup menu. */ - virtual void drawPopupMenuItem (Graphics& g, - int width, int height, - const bool isSeparator, - const bool isActive, - const bool isHighlighted, - const bool isTicked, - const bool hasSubMenu, - const String& text, - const String& shortcutKeyText, - Image* image, - const Colour* const textColour); + /** Checks whether an image is in the cache or not. - /** Returns the size and style of font to use in popup menus. */ - virtual const Font getPopupMenuFont(); + @returns true if the image is currently in the cache + */ + static bool isImageInCache (Image* const imageToLookFor); - virtual void drawPopupMenuUpDownArrow (Graphics& g, - int width, int height, - bool isScrollUpArrow); + /** Increments the reference-count for a cached image. - /** Finds the best size for an item in a popup menu. */ - virtual void getIdealPopupMenuItemSize (const String& text, - const bool isSeparator, - int standardMenuItemHeight, - int& idealWidth, - int& idealHeight); + If the image isn't in the cache, this method won't do anything. + */ + static void incReferenceCount (Image* const image); - virtual int getMenuWindowFlags(); + /** Checks the cache for an image with a particular hashcode. - virtual void drawMenuBarBackground (Graphics& g, int width, int height, - bool isMouseOverBar, - MenuBarComponent& menuBar); + If there's an image in the cache with this hashcode, it will be returned, + otherwise it will return zero. - virtual int getMenuBarItemWidth (MenuBarComponent& menuBar, int itemIndex, const String& itemText); + If an image is returned, it must be released with the release() method + when no longer needed, to maintain the correct reference counts. - virtual const Font getMenuBarFont (MenuBarComponent& menuBar, int itemIndex, const String& itemText); + @param hashCode the hash code that would have been associated with the + image by addImageToCache() + @see addImageToCache + */ + static Image* getFromHashCode (const int64 hashCode); - virtual void drawMenuBarItem (Graphics& g, - int width, int height, - int itemIndex, - const String& itemText, - bool isMouseOverItem, - bool isMenuOpen, - bool isMouseOverBar, - MenuBarComponent& menuBar); + /** Adds an image to the cache with a user-defined hash-code. - virtual void drawComboBox (Graphics& g, int width, int height, - const bool isButtonDown, - int buttonX, int buttonY, - int buttonW, int buttonH, - ComboBox& box); + After calling this, responsibilty for deleting the image will be taken + by the ImageCache. - virtual const Font getComboBoxFont (ComboBox& box); + The image will be initially be given a reference count of 1, so call + the release() method to delete it. - virtual Label* createComboBoxTextBox (ComboBox& box); + @param image the image to add + @param hashCode the hash-code to associate with it + @see getFromHashCode + */ + static void addImageToCache (Image* const image, + const int64 hashCode); - virtual void positionComboBoxText (ComboBox& box, Label& labelToPosition); + /** Changes the amount of time before an unused image will be removed from the cache. - virtual void drawLabel (Graphics& g, Label& label); + By default this is about 5 seconds. + */ + static void setCacheTimeout (const int millisecs); - virtual void drawLinearSlider (Graphics& g, - int x, int y, - int width, int height, - float sliderPos, - float minSliderPos, - float maxSliderPos, - const Slider::SliderStyle style, - Slider& slider); + juce_UseDebuggingNewOperator - virtual void drawLinearSliderBackground (Graphics& g, - int x, int y, - int width, int height, - float sliderPos, - float minSliderPos, - float maxSliderPos, - const Slider::SliderStyle style, - Slider& slider); +private: - virtual void drawLinearSliderThumb (Graphics& g, - int x, int y, - int width, int height, - float sliderPos, - float minSliderPos, - float maxSliderPos, - const Slider::SliderStyle style, - Slider& slider); + CriticalSection lock; + VoidArray images; - virtual int getSliderThumbRadius (Slider& slider); + ImageCache() throw(); + ImageCache (const ImageCache&); + const ImageCache& operator= (const ImageCache&); + ~ImageCache(); - virtual void drawRotarySlider (Graphics& g, - int x, int y, - int width, int height, - float sliderPosProportional, - const float rotaryStartAngle, - const float rotaryEndAngle, - Slider& slider); + void timerCallback(); +}; - virtual Button* createSliderButton (const bool isIncrement); - virtual Label* createSliderTextBox (Slider& slider); +#endif // __JUCE_IMAGECACHE_JUCEHEADER__ +/********* End of inlined file: juce_ImageCache.h *********/ - virtual ImageEffectFilter* getSliderEffect(); +#endif +#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ - virtual void getTooltipSize (const String& tipText, int& width, int& height); +/********* Start of inlined file: juce_ImageConvolutionKernel.h *********/ +#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ +#define __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ - virtual void drawTooltip (Graphics& g, const String& text, int width, int height); +/** + Represents a filter kernel to use in convoluting an image. - virtual Button* createFilenameComponentBrowseButton (const String& text); + @see Image::applyConvolution +*/ +class JUCE_API ImageConvolutionKernel +{ +public: - virtual void layoutFilenameComponent (FilenameComponent& filenameComp, - ComboBox* filenameBox, Button* browseButton); + /** Creates an empty convulution kernel. - virtual void drawCornerResizer (Graphics& g, - int w, int h, - bool isMouseOver, - bool isMouseDragging); + @param size the length of each dimension of the kernel, so e.g. if the size + is 5, it will create a 5x5 kernel + */ + ImageConvolutionKernel (const int size) throw(); - virtual void drawResizableFrame (Graphics& g, - int w, int h, - const BorderSize& borders); + /** Destructor. */ + ~ImageConvolutionKernel() throw(); - virtual void fillResizableWindowBackground (Graphics& g, int w, int h, - const BorderSize& border, - ResizableWindow& window); + /** Resets all values in the kernel to zero. + */ + void clear() throw(); - virtual void drawResizableWindowBorder (Graphics& g, - int w, int h, - const BorderSize& border, - ResizableWindow& window); + /** Sets the value of a specific cell in the kernel. - virtual void drawDocumentWindowTitleBar (DocumentWindow& window, - Graphics& g, int w, int h, - int titleSpaceX, int titleSpaceW, - const Image* icon, - bool drawTitleTextOnLeft); + The x and y parameters must be in the range 0 < x < getKernelSize(). - virtual Button* createDocumentWindowButton (int buttonType); + @see setOverallSum + */ + void setKernelValue (const int x, + const int y, + const float value) throw(); - virtual void positionDocumentWindowButtons (DocumentWindow& window, - int titleBarX, int titleBarY, - int titleBarW, int titleBarH, - Button* minimiseButton, - Button* maximiseButton, - Button* closeButton, - bool positionTitleBarButtonsOnLeft); + /** Rescales all values in the kernel to make the total add up to a fixed value. - virtual int getDefaultMenuBarHeight(); + This will multiply all values in the kernel by (desiredTotalSum / currentTotalSum). + */ + void setOverallSum (const float desiredTotalSum) throw(); - virtual DropShadower* createDropShadowerForComponent (Component* component); + /** Multiplies all values in the kernel by a value. */ + void rescaleAllValues (const float multiplier) throw(); - virtual void drawStretchableLayoutResizerBar (Graphics& g, - int w, int h, - bool isVerticalBar, - bool isMouseOver, - bool isMouseDragging); + /** Intialises the kernel for a gaussian blur. - virtual void drawGroupComponentOutline (Graphics& g, int w, int h, - const String& text, - const Justification& position, - GroupComponent& group); + @param blurRadius this may be larger or smaller than the kernel's actual + size but this will obviously be wasteful or clip at the + edges. Ideally the kernel should be just larger than + (blurRadius * 2). + */ + void createGaussianBlur (const float blurRadius) throw(); - virtual void createTabButtonShape (Path& p, - int width, int height, - int tabIndex, - const String& text, - Button& button, - TabbedButtonBar::Orientation orientation, - const bool isMouseOver, - const bool isMouseDown, - const bool isFrontTab); + /** Returns the size of the kernel. - virtual void fillTabButtonShape (Graphics& g, - const Path& path, - const Colour& preferredBackgroundColour, - int tabIndex, - const String& text, - Button& button, - TabbedButtonBar::Orientation orientation, - const bool isMouseOver, - const bool isMouseDown, - const bool isFrontTab); + E.g. if it's a 3x3 kernel, this returns 3. + */ + int getKernelSize() const throw() { return size; } - virtual void drawTabButtonText (Graphics& g, - int x, int y, int w, int h, - const Colour& preferredBackgroundColour, - int tabIndex, - const String& text, - Button& button, - TabbedButtonBar::Orientation orientation, - const bool isMouseOver, - const bool isMouseDown, - const bool isFrontTab); + /** Returns a 2-dimensional array of the kernel's values. - virtual int getTabButtonOverlap (int tabDepth); - virtual int getTabButtonSpaceAroundImage(); + The size of each dimension of the array will be getKernelSize(). + */ + float** getValues() const throw() { return values; } - virtual int getTabButtonBestWidth (int tabIndex, - const String& text, - int tabDepth, - Button& button); + /** Applies the kernel to an image. - virtual void drawTabButton (Graphics& g, - int w, int h, - const Colour& preferredColour, - int tabIndex, - const String& text, - Button& button, - TabbedButtonBar::Orientation orientation, - const bool isMouseOver, - const bool isMouseDown, - const bool isFrontTab); + @param destImage the image that will receive the resultant convoluted pixels. + @param sourceImage an optional source image to read from - if this is 0, then the + destination image will be used as the source. If an image is + specified, it must be exactly the same size and type as the destination + image. + @param x the region of the image to apply the filter to + @param y the region of the image to apply the filter to + @param width the region of the image to apply the filter to + @param height the region of the image to apply the filter to + */ + void applyToImage (Image& destImage, + const Image* sourceImage, + int x, + int y, + int width, + int height) const; - virtual void drawTabAreaBehindFrontButton (Graphics& g, - int w, int h, - TabbedButtonBar& tabBar, - TabbedButtonBar::Orientation orientation); + juce_UseDebuggingNewOperator - virtual Button* createTabBarExtrasButton(); +private: + HeapBlock values; + const int size; - virtual void drawImageButton (Graphics& g, Image* image, - int imageX, int imageY, int imageW, int imageH, - const Colour& overlayColour, - float imageOpacity, - ImageButton& button); + // no reason not to implement these one day.. + ImageConvolutionKernel (const ImageConvolutionKernel&); + const ImageConvolutionKernel& operator= (const ImageConvolutionKernel&); +}; - virtual void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header); +#endif // __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ +/********* End of inlined file: juce_ImageConvolutionKernel.h *********/ - virtual void drawTableHeaderColumn (Graphics& g, const String& columnName, int columnId, - int width, int height, - bool isMouseOver, bool isMouseDown, - int columnFlags); +#endif +#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ - virtual void paintToolbarBackground (Graphics& g, int width, int height, Toolbar& toolbar); +/********* Start of inlined file: juce_ImageFileFormat.h *********/ +#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ +#define __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ - virtual Button* createToolbarMissingItemsButton (Toolbar& toolbar); +/** + Base-class for codecs that can read and write image file formats such + as PNG, JPEG, etc. - virtual void paintToolbarButtonBackground (Graphics& g, int width, int height, - bool isMouseOver, bool isMouseDown, - ToolbarItemComponent& component); + This class also contains static methods to make it easy to load images + from files, streams or from memory. - virtual void paintToolbarButtonLabel (Graphics& g, int x, int y, int width, int height, - const String& text, ToolbarItemComponent& component); + @see Image, ImageCache +*/ +class JUCE_API ImageFileFormat +{ +protected: - virtual void drawPropertyPanelSectionHeader (Graphics& g, const String& name, - bool isOpen, int width, int height); + /** Creates an ImageFormat. */ + ImageFileFormat() throw() {} - virtual void drawPropertyComponentBackground (Graphics& g, int width, int height, - PropertyComponent& component); +public: + /** Destructor. */ + virtual ~ImageFileFormat() throw() {} - virtual void drawPropertyComponentLabel (Graphics& g, int width, int height, - PropertyComponent& component); + /** Returns a description of this file format. - virtual const Rectangle getPropertyComponentContentPosition (PropertyComponent& component); + E.g. "JPEG", "PNG" + */ + virtual const String getFormatName() = 0; - virtual void drawLevelMeter (Graphics& g, int width, int height, float level); + /** Returns true if the given stream seems to contain data that this format + understands. - virtual void drawKeymapChangeButton (Graphics& g, int width, int height, Button& button, const String& keyDescription); + The format class should only read the first few bytes of the stream and sniff + for header bytes that it understands. - /** + @see decodeImage */ - virtual void playAlertSound(); - - /** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */ - static void drawGlassSphere (Graphics& g, - const float x, const float y, - const float diameter, - const Colour& colour, - const float outlineThickness) throw(); - - static void drawGlassPointer (Graphics& g, - const float x, const float y, - const float diameter, - const Colour& colour, const float outlineThickness, - const int direction) throw(); + virtual bool canUnderstand (InputStream& input) = 0; - /** Utility function to draw a shiny, glassy oblong (for text buttons). */ - static void drawGlassLozenge (Graphics& g, - const float x, const float y, - const float width, const float height, - const Colour& colour, - const float outlineThickness, - const float cornerSize, - const bool flatOnLeft, const bool flatOnRight, - const bool flatOnTop, const bool flatOnBottom) throw(); + /** Tries to decode and return an image from the given stream. - juce_UseDebuggingNewOperator + This will be called for an image format after calling its canUnderStand() method + to see if it can handle the stream. -protected: - // xxx the following methods are only here to cause a compiler error, because they've been - // deprecated or their parameters have changed. Hopefully these definitions should cause an - // error if you try to build a subclass with the old versions. - virtual int drawTickBox (Graphics&, int, int, int, int, bool, const bool, const bool, const bool) { return 0; } - virtual int drawProgressBar (Graphics&, int, int, int, int, float) { return 0; } - virtual int drawProgressBar (Graphics&, ProgressBar&, int, int, int, int, float) { return 0; } - virtual void getTabButtonBestWidth (int, const String&, int) {} - virtual int drawTreeviewPlusMinusBox (Graphics&, int, int, int, int, bool) { return 0; } + @param input the stream to read the data from. The stream will be positioned + at the start of the image data (but this may not necessarily + be position 0) + @returns the image that was decoded, or 0 if it fails. It's the + caller's responsibility to delete this image when no longer needed. + @see loadFrom + */ + virtual Image* decodeImage (InputStream& input) = 0; -private: - friend void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI(); - static void clearDefaultLookAndFeel() throw(); // called at shutdown + /** Attempts to write an image to a stream. - Array colourIds; - Array colours; + To specify extra information like encoding quality, there will be appropriate parameters + in the subclasses of the specific file types. - // default typeface names - String defaultSans, defaultSerif, defaultFixed; + @returns true if it nothing went wrong. + */ + virtual bool writeImageToStream (const Image& sourceImage, + OutputStream& destStream) = 0; - void drawShinyButtonShape (Graphics& g, - float x, float y, float w, float h, float maxCornerSize, - const Colour& baseColour, - const float strokeWidth, - const bool flatOnLeft, - const bool flatOnRight, - const bool flatOnTop, - const bool flatOnBottom) throw(); + /** Tries the built-in decoders to see if it can find one to read this stream. - LookAndFeel (const LookAndFeel&); - const LookAndFeel& operator= (const LookAndFeel&); -}; + There are currently built-in decoders for PNG, JPEG and GIF formats. -#endif // __JUCE_LOOKANDFEEL_JUCEHEADER__ -/********* End of inlined file: juce_LookAndFeel.h *********/ + The object that is returned should not be deleted by the caller. -#endif -#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ + @see canUnderstand, decodeImage, loadFrom + */ + static ImageFileFormat* findImageFormatForStream (InputStream& input); -/********* Start of inlined file: juce_OldSchoolLookAndFeel.h *********/ -#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ -#define __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ + /** Tries to load an image from a stream. -/** - The original Juce look-and-feel. + This will use the findImageFormatForStream() method to locate a suitable + codec, and use that to load the image. -*/ -class JUCE_API OldSchoolLookAndFeel : public LookAndFeel -{ -public: + @returns the image that was decoded, or 0 if it fails to load one. It's the + caller's responsibility to delete this image when no longer needed. + */ + static Image* loadFrom (InputStream& input); - /** Creates the default JUCE look and feel. */ - OldSchoolLookAndFeel(); + /** Tries to load an image from a file. - /** Destructor. */ - virtual ~OldSchoolLookAndFeel(); + This will use the findImageFormatForStream() method to locate a suitable + codec, and use that to load the image. - /** Draws the lozenge-shaped background for a standard button. */ - virtual void drawButtonBackground (Graphics& g, - Button& button, - const Colour& backgroundColour, - bool isMouseOverButton, - bool isButtonDown); + @returns the image that was decoded, or 0 if it fails to load one. It's the + caller's responsibility to delete this image when no longer needed. + */ + static Image* loadFrom (const File& file); - /** Draws the contents of a standard ToggleButton. */ - virtual void drawToggleButton (Graphics& g, - ToggleButton& button, - bool isMouseOverButton, - bool isButtonDown); + /** Tries to load an image from a block of raw image data. - virtual void drawTickBox (Graphics& g, - Component& component, - int x, int y, int w, int h, - const bool ticked, - const bool isEnabled, - const bool isMouseOverButton, - const bool isButtonDown); + This will use the findImageFormatForStream() method to locate a suitable + codec, and use that to load the image. - virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar, - int width, int height, - double progress, const String& textToShow); + @returns the image that was decoded, or 0 if it fails to load one. It's the + caller's responsibility to delete this image when no longer needed. + */ + static Image* loadFrom (const void* rawData, + const int numBytesOfData); - virtual void drawScrollbarButton (Graphics& g, - ScrollBar& scrollbar, - int width, int height, - int buttonDirection, - bool isScrollbarVertical, - bool isMouseOverButton, - bool isButtonDown); +}; - virtual void drawScrollbar (Graphics& g, - ScrollBar& scrollbar, - int x, int y, - int width, int height, - bool isScrollbarVertical, - int thumbStartPosition, - int thumbSize, - bool isMouseOver, - bool isMouseDown); +/** + A type of ImageFileFormat for reading and writing PNG files. - virtual ImageEffectFilter* getScrollbarEffect(); + @see ImageFileFormat, JPEGImageFormat +*/ +class JUCE_API PNGImageFormat : public ImageFileFormat +{ +public: - virtual void drawTextEditorOutline (Graphics& g, - int width, int height, - TextEditor& textEditor); + PNGImageFormat() throw(); + ~PNGImageFormat() throw(); - /** Fills the background of a popup menu component. */ - virtual void drawPopupMenuBackground (Graphics& g, int width, int height); + const String getFormatName(); + bool canUnderstand (InputStream& input); - virtual void drawMenuBarBackground (Graphics& g, int width, int height, - bool isMouseOverBar, - MenuBarComponent& menuBar); + Image* decodeImage (InputStream& input); - virtual void drawComboBox (Graphics& g, int width, int height, - const bool isButtonDown, - int buttonX, int buttonY, - int buttonW, int buttonH, - ComboBox& box); + bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); +}; - virtual const Font getComboBoxFont (ComboBox& box); +/** + A type of ImageFileFormat for reading and writing JPEG files. - virtual void drawLinearSlider (Graphics& g, - int x, int y, - int width, int height, - float sliderPos, - float minSliderPos, - float maxSliderPos, - const Slider::SliderStyle style, - Slider& slider); + @see ImageFileFormat, PNGImageFormat +*/ +class JUCE_API JPEGImageFormat : public ImageFileFormat +{ +public: - virtual int getSliderThumbRadius (Slider& slider); + JPEGImageFormat() throw(); + ~JPEGImageFormat() throw(); - virtual Button* createSliderButton (const bool isIncrement); + /** Specifies the quality to be used when writing a JPEG file. - virtual ImageEffectFilter* getSliderEffect(); + @param newQuality a value 0 to 1.0, where 0 is low quality, 1.0 is best, or + any negative value is "default" quality + */ + void setQuality (const float newQuality); - virtual void drawCornerResizer (Graphics& g, - int w, int h, - bool isMouseOver, - bool isMouseDragging); + const String getFormatName(); - virtual Button* createDocumentWindowButton (int buttonType); + bool canUnderstand (InputStream& input); - virtual void positionDocumentWindowButtons (DocumentWindow& window, - int titleBarX, int titleBarY, - int titleBarW, int titleBarH, - Button* minimiseButton, - Button* maximiseButton, - Button* closeButton, - bool positionTitleBarButtonsOnLeft); + Image* decodeImage (InputStream& input); - juce_UseDebuggingNewOperator + bool writeImageToStream (const Image& sourceImage, OutputStream& destStream); private: - DropShadowEffect scrollbarShadow; - - OldSchoolLookAndFeel (const OldSchoolLookAndFeel&); - const OldSchoolLookAndFeel& operator= (const OldSchoolLookAndFeel&); + float quality; }; -#endif // __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ -/********* End of inlined file: juce_OldSchoolLookAndFeel.h *********/ +#endif // __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ +/********* End of inlined file: juce_ImageFileFormat.h *********/ #endif #ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ diff --git a/src/audio/audio_file_formats/juce_AudioCDReader.h b/src/audio/audio_file_formats/juce_AudioCDReader.h index c4739b6af2..1ee92fa095 100644 --- a/src/audio/audio_file_formats/juce_AudioCDReader.h +++ b/src/audio/audio_file_formats/juce_AudioCDReader.h @@ -29,6 +29,7 @@ #if JUCE_USE_CDREADER #include "juce_AudioFormatReader.h" +#include "../../containers/juce_Array.h" #include "../../text/juce_StringArray.h" #if JUCE_MAC #include "../../io/files/juce_File.h" diff --git a/src/audio/audio_file_formats/juce_AudioFormat.h b/src/audio/audio_file_formats/juce_AudioFormat.h index 14c832678e..213d200b95 100644 --- a/src/audio/audio_file_formats/juce_AudioFormat.h +++ b/src/audio/audio_file_formats/juce_AudioFormat.h @@ -28,6 +28,7 @@ #include "juce_AudioFormatReader.h" #include "juce_AudioFormatWriter.h" +#include "../../containers/juce_Array.h" //============================================================================== diff --git a/src/audio/audio_file_formats/juce_AudioFormatManager.h b/src/audio/audio_file_formats/juce_AudioFormatManager.h index 47f8c7490a..78c3ae44af 100644 --- a/src/audio/audio_file_formats/juce_AudioFormatManager.h +++ b/src/audio/audio_file_formats/juce_AudioFormatManager.h @@ -28,6 +28,7 @@ #include "juce_AudioFormat.h" #include "../../core/juce_Singleton.h" +#include "../../containers/juce_VoidArray.h" //============================================================================== diff --git a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp index 6a141b2de9..b99fc0c43f 100644 --- a/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_QuickTimeAudioFormat.cpp @@ -85,7 +85,7 @@ public: lastThreadId (0), dataHandle (0) { - bufferList = (AudioBufferList*) juce_calloc (256); + bufferList.calloc (256, 1); #ifdef WIN32 if (InitializeQTML (0) != noErr) @@ -143,24 +143,22 @@ public: if (err != noErr) return; - AudioChannelLayout* const qt_audio_channel_layout - = (AudioChannelLayout*) juce_calloc (output_layout_size); + HeapBlock qt_audio_channel_layout; + qt_audio_channel_layout.calloc (output_layout_size, 1); err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, output_layout_size, qt_audio_channel_layout, 0); - qt_audio_channel_layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; + qt_audio_channel_layout[0].mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; err = MovieAudioExtractionSetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, - sizeof (qt_audio_channel_layout), + output_layout_size, qt_audio_channel_layout); - juce_free (qt_audio_channel_layout); - err = MovieAudioExtractionGetProperty (extractor, kQTPropertyClass_MovieAudioExtraction_Audio, kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, @@ -223,7 +221,6 @@ public: DisposeMovie (movie); juce_free (bufferList->mBuffers[0].mData); - juce_free (bufferList); #if JUCE_MAC ExitMoviesOnThread (); @@ -308,7 +305,7 @@ private: Thread::ThreadID lastThreadId; MovieAudioExtractionRef extractor; AudioStreamBasicDescription inputStreamDesc; - AudioBufferList* bufferList; + HeapBlock bufferList; Handle dataHandle; /*OSErr readMovieStream (long offset, long size, void* dataPtr) diff --git a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp index 927eeb6ffd..17324d65d6 100644 --- a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp @@ -276,17 +276,17 @@ public: bwavSize = length; // Broadcast-wav extension chunk.. - BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); + HeapBlock bwav; + bwav.calloc (jmax (length + 1, (int) sizeof (BWAVChunk)), 1); input->read (bwav, length); bwav->copyTo (metadataValues); - juce_free (bwav); } else if (chunkType == chunkName ("smpl")) { - SMPLChunk* const smpl = (SMPLChunk*) juce_calloc (jmax (length + 1, (int) sizeof (SMPLChunk))); + HeapBlock smpl; + smpl.calloc (jmax (length + 1, (int) sizeof (SMPLChunk)), 1); input->read (smpl, length); smpl->copyTo (metadataValues, length); - juce_free (smpl); } else if (chunkEnd <= input->getPosition()) { diff --git a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h index 54e84ec4cc..b2f750b8ed 100644 --- a/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h +++ b/src/audio/audio_sources/juce_ChannelRemappingAudioSource.h @@ -28,6 +28,7 @@ #include "juce_AudioSource.h" #include "../../text/juce_XmlElement.h" +#include "../../containers/juce_Array.h" //============================================================================== diff --git a/src/audio/dsp/juce_AudioSampleBuffer.cpp b/src/audio/dsp/juce_AudioSampleBuffer.cpp index ccb6be81c4..1cc542eb32 100644 --- a/src/audio/dsp/juce_AudioSampleBuffer.cpp +++ b/src/audio/dsp/juce_AudioSampleBuffer.cpp @@ -41,18 +41,35 @@ AudioSampleBuffer::AudioSampleBuffer (const int numChannels_, jassert (numSamples >= 0); jassert (numChannels_ > 0); - allocatedBytes = numChannels * numSamples * sizeof (float) + 32; - allocatedData = (float*) juce_malloc (allocatedBytes); - channels = (float**) juce_malloc ((numChannels_ + 1) * sizeof (float*)); + allocateData(); +} + +AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) throw() + : numChannels (other.numChannels), + size (other.size) +{ + allocateData(); + const int numBytes = size * sizeof (float); + + for (int i = 0; i < numChannels; ++i) + memcpy (channels[i], other.channels[i], numBytes); +} - float* chan = allocatedData; - for (int i = 0; i < numChannels_; ++i) +void AudioSampleBuffer::allocateData() +{ + const int channelListSize = (numChannels + 1) * sizeof (float*); + allocatedBytes = numChannels * size * sizeof (float) + channelListSize + 32; + allocatedData.malloc (allocatedBytes); + channels = (float**) allocatedData; + + float* chan = (float*) (allocatedData + channelListSize); + for (int i = 0; i < numChannels; ++i) { channels[i] = chan; - chan += numSamples; + chan += size; } - channels [numChannels_] = 0; + channels [numChannels] = 0; } AudioSampleBuffer::AudioSampleBuffer (float** dataToReferTo, @@ -60,84 +77,49 @@ AudioSampleBuffer::AudioSampleBuffer (float** dataToReferTo, const int numSamples) throw() : numChannels (numChannels_), size (numSamples), - allocatedBytes (0), - allocatedData (0) + allocatedBytes (0) { jassert (numChannels_ > 0); - - // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) - if (numChannels_ < numElementsInArray (preallocatedChannelSpace)) - channels = (float**) preallocatedChannelSpace; - else - channels = (float**) juce_malloc ((numChannels_ + 1) * sizeof (float*)); - - for (int i = 0; i < numChannels_; ++i) - { - // you have to pass in the same number of valid pointers as numChannels - jassert (dataToReferTo[i] != 0); - - channels[i] = dataToReferTo[i]; - } - - channels [numChannels_] = 0; + allocateChannels (dataToReferTo); } void AudioSampleBuffer::setDataToReferTo (float** dataToReferTo, - const int numChannels_, - const int numSamples) throw() + const int newNumChannels, + const int newNumSamples) throw() { - jassert (numChannels_ > 0); + jassert (newNumChannels > 0); - juce_free (allocatedData); - allocatedData = 0; allocatedBytes = 0; + allocatedData.free(); - if (numChannels_ > numChannels) - channels = (float**) juce_realloc (channels, (numChannels_ + 1) * sizeof (float*)); - - numChannels = numChannels_; - size = numSamples; + numChannels = newNumChannels; + size = newNumSamples; - for (int i = 0; i < numChannels_; ++i) - { - // you have to pass in the same number of valid pointers as numChannels - jassert (dataToReferTo[i] != 0); - - channels[i] = dataToReferTo[i]; - } - - channels [numChannels_] = 0; + allocateChannels (dataToReferTo); } -AudioSampleBuffer::AudioSampleBuffer (const AudioSampleBuffer& other) throw() - : numChannels (other.numChannels), - size (other.size) +void AudioSampleBuffer::allocateChannels (float** const dataToReferTo) { - channels = (float**) juce_malloc ((other.numChannels + 1) * sizeof (float*)); - - if (other.allocatedData != 0) + // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) + if (numChannels < numElementsInArray (preallocatedChannelSpace)) { - allocatedBytes = numChannels * size * sizeof (float) + 32; - allocatedData = (float*) juce_malloc (allocatedBytes); - - memcpy (allocatedData, other.allocatedData, allocatedBytes); - - float* chan = allocatedData; - for (int i = 0; i < numChannels; ++i) - { - channels[i] = chan; - chan += size; - } - - channels [numChannels] = 0; + channels = (float**) preallocatedChannelSpace; } else { - allocatedData = 0; - allocatedBytes = 0; + allocatedData.malloc (numChannels + 1, sizeof (float*)); + channels = (float**) allocatedData; + } + + for (int i = 0; i < numChannels; ++i) + { + // you have to pass in the same number of valid pointers as numChannels + jassert (dataToReferTo[i] != 0); - memcpy (channels, other.channels, sizeof (channels)); + channels[i] = dataToReferTo[i]; } + + channels [numChannels] = 0; } const AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& other) throw() @@ -157,10 +139,6 @@ const AudioSampleBuffer& AudioSampleBuffer::operator= (const AudioSampleBuffer& AudioSampleBuffer::~AudioSampleBuffer() throw() { - juce_free (allocatedData); - - if (channels != (float**) preallocatedChannelSpace) - juce_free (channels); } void AudioSampleBuffer::setSize (const int newNumChannels, @@ -173,26 +151,29 @@ void AudioSampleBuffer::setSize (const int newNumChannels, if (newNumSamples != size || newNumChannels != numChannels) { - const int newTotalBytes = newNumChannels * newNumSamples * sizeof (float) + 32; + const int channelListSize = (newNumChannels + 1) * sizeof (float*); + const int newTotalBytes = (newNumChannels * newNumSamples * sizeof (float)) + channelListSize + 32; if (keepExistingContent) { - float* const newData = (clearExtraSpace) ? (float*) juce_calloc (newTotalBytes) - : (float*) juce_malloc (newTotalBytes); + HeapBlock newData; + newData.allocate (newTotalBytes, clearExtraSpace); - const int sizeToCopy = sizeof (float) * jmin (newNumSamples, size); + const int numChansToCopy = jmin (numChannels, newNumChannels); + const int numBytesToCopy = sizeof (float) * jmin (newNumSamples, size); - for (int i = jmin (newNumChannels, numChannels); --i >= 0;) + float** const newChannels = (float**) newData; + float* newChan = (float*) (newData + channelListSize); + for (int i = 0; i < numChansToCopy; ++i) { - memcpy (newData + i * newNumSamples, - channels[i], - sizeToCopy); + memcpy (newChan, channels[i], numBytesToCopy); + newChannels[i] = newChan; + newChan += newNumSamples; } - juce_free (allocatedData); - - allocatedData = newData; + allocatedData.swapWith (newData); allocatedBytes = newTotalBytes; + channels = (float**) allocatedData; } else { @@ -203,29 +184,22 @@ void AudioSampleBuffer::setSize (const int newNumChannels, } else { - juce_free (allocatedData); - - allocatedData = (clearExtraSpace) ? (float*) juce_calloc (newTotalBytes) - : (float*) juce_malloc (newTotalBytes); allocatedBytes = newTotalBytes; + allocatedData.allocate (newTotalBytes, clearExtraSpace); + channels = (float**) allocatedData; } - } - - size = newNumSamples; - - if (newNumChannels > numChannels) - channels = (float**) juce_realloc (channels, (newNumChannels + 1) * sizeof (float*)); - numChannels = newNumChannels; - - float* chan = allocatedData; - for (int i = 0; i < newNumChannels; ++i) - { - channels[i] = chan; - chan += size; + float* chan = (float*) (allocatedData + channelListSize); + for (int i = 0; i < newNumChannels; ++i) + { + channels[i] = chan; + chan += newNumSamples; + } } channels [newNumChannels] = 0; + size = newNumSamples; + numChannels = newNumChannels; } } @@ -679,7 +653,8 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, } else { - chans[0] = (int*) juce_malloc (sizeof (int) * numSamples * 2); + HeapBlock tempBuffer (numSamples * 2); + chans[0] = tempBuffer; if (numChannels > 1) chans[1] = chans[0] + numSamples; @@ -711,8 +686,6 @@ void AudioSampleBuffer::writeToAudioWriter (AudioFormatWriter* writer, } writer->write ((const int**) chans, numSamples); - - juce_free (chans[0]); } } } diff --git a/src/audio/dsp/juce_AudioSampleBuffer.h b/src/audio/dsp/juce_AudioSampleBuffer.h index 2d3ab4627c..04cc44c425 100644 --- a/src/audio/dsp/juce_AudioSampleBuffer.h +++ b/src/audio/dsp/juce_AudioSampleBuffer.h @@ -26,6 +26,7 @@ #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ #define __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ +#include "../../containers/juce_HeapBlock.h" class AudioFormatReader; class AudioFormatWriter; @@ -425,8 +426,11 @@ public: private: int numChannels, size, allocatedBytes; float** channels; - float* allocatedData; + HeapBlock allocatedData; float* preallocatedChannelSpace [32]; + + void allocateData(); + void allocateChannels (float** const dataToReferTo); }; diff --git a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm index 9392fb7205..fe0f73caba 100644 --- a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm @@ -276,7 +276,7 @@ private: CriticalSection lock; bool initialised, wantsMidiMessages, wasPlaying; - AudioBufferList* outputBufferList; + HeapBlock outputBufferList; AudioTimeStamp timeStamp; AudioSampleBuffer* currentBuffer; @@ -375,7 +375,6 @@ AudioUnitPluginInstance::AudioUnitPluginInstance (const String& fileOrIdentifier initialised (false), wantsMidiMessages (false), audioUnit (0), - outputBufferList (0), currentBuffer (0) { try @@ -419,8 +418,6 @@ AudioUnitPluginInstance::~AudioUnitPluginInstance() audioUnit = 0; } } - - juce_free (outputBufferList); } bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIdentifier) @@ -602,8 +599,7 @@ void AudioUnitPluginInstance::prepareToPlay (double sampleRate_, kAudioUnitScope_Output, 0, &stream, sizeof (stream)); - juce_free (outputBufferList); - outputBufferList = (AudioBufferList*) juce_calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1)); + outputBufferList.calloc (sizeof (AudioBufferList) + sizeof (AudioBuffer) * (numOuts + 1), 1); outputBufferList->mNumberBuffers = numOuts; for (int i = numOuts; --i >= 0;) @@ -627,8 +623,7 @@ void AudioUnitPluginInstance::releaseResources() AudioUnitReset (audioUnit, kAudioUnitScope_Output, 0); AudioUnitReset (audioUnit, kAudioUnitScope_Global, 0); - juce_free (outputBufferList); - outputBufferList = 0; + outputBufferList.free(); currentBuffer = 0; } } @@ -901,7 +896,8 @@ private: && AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr) { - AudioUnitCocoaViewInfo* info = (AudioUnitCocoaViewInfo*) juce_calloc (dataSize); + HeapBlock info; + info.calloc (dataSize, 1); if (AudioUnitGetProperty (plugin.audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, info, &dataSize) == noErr) @@ -926,8 +922,6 @@ private: CFRelease (info->mCocoaAUViewBundleLocation); } } - - juce_free (info); } if (createGenericViewIfNeeded && (pluginView == 0)) diff --git a/src/audio/plugins/formats/juce_VSTMidiEventList.h b/src/audio/plugins/formats/juce_VSTMidiEventList.h index d0d8dbd655..f721787bc2 100644 --- a/src/audio/plugins/formats/juce_VSTMidiEventList.h +++ b/src/audio/plugins/formats/juce_VSTMidiEventList.h @@ -40,7 +40,7 @@ class VSTMidiEventList public: //============================================================================== VSTMidiEventList() - : events (0), numEventsUsed (0), numEventsAllocated (0) + : numEventsUsed (0), numEventsAllocated (0) { } @@ -138,9 +138,9 @@ public: const int size = 20 + sizeof (VstEvent*) * numEventsNeeded; if (events == 0) - events = (VstEvents*) juce_calloc (size); + events.calloc (size, 1); else - events = (VstEvents*) juce_realloc (events, size); + events.realloc (size, 1); for (int i = numEventsAllocated; i < numEventsNeeded; ++i) { @@ -170,15 +170,14 @@ public: juce_free (e); } - juce_free (events); - events = 0; + events.free(); numEventsUsed = 0; numEventsAllocated = 0; } } //============================================================================== - VstEvents* events; + HeapBlock events; private: int numEventsUsed, numEventsAllocated; diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp index fecf0a5dd6..b838698eb2 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -769,7 +769,7 @@ private: MidiBuffer incomingMidi; VSTMidiEventList midiEventsToSend; VstTimeInfo vstHostTime; - float** channels; + HeapBlock channels; ReferenceCountedObjectPtr module; @@ -808,7 +808,6 @@ VSTPluginInstance::VSTPluginInstance (const ReferenceCountedObjectPtr initialDelay); - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * jmax (16, getNumOutputChannels() + 2, getNumInputChannels() + 2)); + channels.calloc (jmax (16, getNumOutputChannels(), getNumInputChannels()) + 2); vstHostTime.tempo = 120.0; vstHostTime.timeSigNumerator = 4; @@ -1020,8 +1015,7 @@ void VSTPluginInstance::releaseResources() incomingMidi.clear(); midiEventsToSend.freeEvents(); - juce_free (channels); - channels = 0; + channels.free(); } void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, diff --git a/src/audio/processors/juce_AudioProcessorGraph.cpp b/src/audio/processors/juce_AudioProcessorGraph.cpp index dc8f2b25cd..571c152e7f 100644 --- a/src/audio/processors/juce_AudioProcessorGraph.cpp +++ b/src/audio/processors/juce_AudioProcessorGraph.cpp @@ -508,7 +508,7 @@ public: totalChans (jmax (1, totalChans_)), midiBufferToUse (midiBufferToUse_) { - channels = (float**) juce_calloc (sizeof (float*) * totalChans); + channels.calloc (totalChans); while (audioChannelsToUse.size() < totalChans) audioChannelsToUse.add (0); @@ -516,7 +516,6 @@ public: ~ProcessBufferOp() throw() { - juce_free (channels); } void perform (AudioSampleBuffer& sharedBufferChans, const OwnedArray & sharedMidiBuffers, const int numSamples) throw() @@ -534,7 +533,7 @@ public: private: Array audioChannelsToUse; - float** channels; + HeapBlock channels; int totalChans; int midiBufferToUse; diff --git a/src/containers/juce_BitArray.cpp b/src/containers/juce_BitArray.cpp index 77ed1a4f42..edc3620e97 100644 --- a/src/containers/juce_BitArray.cpp +++ b/src/containers/juce_BitArray.cpp @@ -39,7 +39,7 @@ BitArray::BitArray() throw() highestBit (-1), negative (false) { - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); } BitArray::BitArray (const int value) throw() @@ -47,7 +47,7 @@ BitArray::BitArray (const int value) throw() highestBit (31), negative (value < 0) { - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); values[0] = abs (value); highestBit = getHighestBit(); } @@ -57,7 +57,7 @@ BitArray::BitArray (int64 value) throw() highestBit (63), negative (value < 0) { - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); if (value < 0) value = -value; @@ -72,7 +72,7 @@ BitArray::BitArray (const unsigned int value) throw() highestBit (31), negative (false) { - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); values[0] = value; highestBit = getHighestBit(); } @@ -82,28 +82,23 @@ BitArray::BitArray (const BitArray& other) throw() highestBit (other.getHighestBit()), negative (other.negative) { - const int bytes = sizeof (unsigned int) * (numValues + 1); - values = (unsigned int*) juce_malloc (bytes); - memcpy (values, other.values, bytes); + values.malloc (numValues + 1); + memcpy (values, other.values, sizeof (unsigned int) * (numValues + 1)); } BitArray::~BitArray() throw() { - juce_free (values); } const BitArray& BitArray::operator= (const BitArray& other) throw() { if (this != &other) { - juce_free (values); - highestBit = other.getHighestBit(); numValues = jmax (4, (highestBit >> 5) + 1); negative = other.negative; - const int memSize = sizeof (unsigned int) * (numValues + 1); - values = (unsigned int*)juce_malloc (memSize); - memcpy (values, other.values, memSize); + values.malloc (numValues + 1); + memcpy (values, other.values, sizeof (unsigned int) * (numValues + 1)); } return *this; @@ -167,9 +162,8 @@ void BitArray::clear() throw() { if (numValues > 16) { - juce_free (values); numValues = 4; - values = (unsigned int*) juce_calloc (sizeof (unsigned int) * (numValues + 1)); + values.calloc (numValues + 1); } else { @@ -821,7 +815,7 @@ void BitArray::ensureSize (const int numVals) throw() { int oldSize = numValues; numValues = ((numVals + 2) * 3) / 2; - values = (unsigned int*) juce_realloc (values, sizeof (unsigned int) * numValues + 4); + values.realloc (numValues + 1); while (oldSize < numValues) values [oldSize++] = 0; diff --git a/src/containers/juce_BitArray.h b/src/containers/juce_BitArray.h index 629f1ea074..6fd13990c9 100644 --- a/src/containers/juce_BitArray.h +++ b/src/containers/juce_BitArray.h @@ -28,6 +28,7 @@ #include "../text/juce_String.h" #include "juce_Array.h" +#include "juce_HeapBlock.h" class MemoryBlock; @@ -334,7 +335,7 @@ public: private: void ensureSize (const int numVals) throw(); - unsigned int* values; + HeapBlock values; int numValues, highestBit; bool negative; }; diff --git a/src/containers/juce_HeapBlock.h b/src/containers/juce_HeapBlock.h new file mode 100644 index 0000000000..cc42a34e86 --- /dev/null +++ b/src/containers/juce_HeapBlock.h @@ -0,0 +1,240 @@ +/* + ============================================================================== + + 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_HEAPBLOCK_JUCEHEADER__ +#define __JUCE_HEAPBLOCK_JUCEHEADER__ + + +//============================================================================== +/** + Very simple container class to hold a pointer to some data on the heap. + + When you need to allocate some heap storage for something, always try to use + this class instead of allocating the memory directly using malloc/free. + + A HeapBlock object can be treated in pretty much exactly the same way + as an char*, but as long as you allocate it on the stack or as a class member, + it's almost impossible for it to leak memory. + + It also makes your code much more concise and readable than doing the same thing + using direct allocations, + + E.g. instead of this: + @code + int* temp = (int*) juce_malloc (1024 * sizeof (int)); + memcpy (temp, xyz, 1024 * sizeof (int)); + juce_free (temp); + temp = (int*) juce_calloc (2048 * sizeof (int)); + temp[0] = 1234; + memcpy (foobar, temp, 2048 * sizeof (int)); + juce_free (temp); + @endcode + + ..you could just write this: + @code + HeapBlock temp (1024); + memcpy (temp, xyz, 1024 * sizeof (int)); + temp.calloc (2048); + temp[0] = 1234; + memcpy (foobar, temp, 2048 * sizeof (int)); + @endcode + + The class is extremely lightweight, containing only a pointer to the + data, and exposes malloc/realloc/calloc/free methods that do the same jobs + as their less object-oriented counterparts. Despite adding safety, you probably + won't sacrifice any performance by using this in place of normal pointers. + + @see Array, OwnedArray, MemoryBlock +*/ +template +class HeapBlock +{ +public: + //============================================================================== + /** Creates a HeapBlock which is initially just a null pointer. + + After creation, you can resize the array using the malloc(), calloc(), + or realloc() methods. + */ + HeapBlock() : data (0) + { + } + + /** Creates a HeapBlock containing a number of elements. + + The contents of the block are undefined, as it will have been created by a + malloc call. + + If you want an array of zero values, you can use the calloc() method instead. + */ + HeapBlock (const int numElements) + : data ((ElementType*) ::juce_malloc (numElements * sizeof (ElementType))) + { + } + + /** Destructor. + + This will free the data, if any has been allocated. + */ + ~HeapBlock() + { + ::juce_free (data); + } + + //============================================================================== + /** Returns a raw pointer to the allocated data. + This may be a null pointer if the data hasn't yet been allocated, or if it has been + freed by calling the free() method. + */ + inline operator ElementType*() const { return data; } + + /** Returns a void pointer to the allocated data. + This may be a null pointer if the data hasn't yet been allocated, or if it has been + freed by calling the free() method. + */ + inline operator void*() const { return (void*) data; } + + /** Lets you use indirect calls to the first element in the array. + Obviously this will cause problems if the array hasn't been initialised, because it'll + be referencing a null pointer. + */ + inline ElementType* operator->() const { return data; } + + /** Returns a pointer to the data by casting it to any type you need. + */ + template + inline operator CastType*() const { return (CastType*) data; } + + /** Returns a reference to one of the data elements. + Obviously there's no bounds-checking here, as this object is just a dumb pointer and + has no idea of the size it currently has allocated. + */ + inline ElementType& operator[] (const pointer_sized_int index) const { return data [index]; } + + /** Returns a pointer to a data element at an offset from the start of the array. + This is the same as doing pointer arithmetic on the raw pointer itself. + */ + inline ElementType* operator+ (const pointer_sized_int index) const { return data + index; } + + /** Returns a reference to the raw data pointer. + Beware that the pointer returned here will become invalid as soon as you call + any of the allocator methods on this object! + */ + inline ElementType** operator&() const { return (ElementType**) &data; } + + //============================================================================== + /** Compares the pointer with another pointer. + This can be handy for checking whether this is a null pointer. + */ + inline bool operator== (const ElementType* const otherPointer) const { return otherPointer == data; } + + /** Compares the pointer with another pointer. + This can be handy for checking whether this is a null pointer. + */ + inline bool operator!= (const ElementType* const otherPointer) const { return otherPointer != data; } + + //============================================================================== + /** Allocates a specified amount of memory. + + This uses the normal malloc to allocate an amount of memory for this object. + Any previously allocated memory will be freed by this method. + + The number of bytes allocated will be (newNumElements * elementSize). Normally + you wouldn't need to specify the second parameter, but it can be handy if you need + to allocate a size in bytes rather than in terms of the number of elements. + + The data that is allocated will be freed when this object is deleted, or when you + call free() or any of the allocation methods. + */ + void malloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + ::juce_free (data); + data = (ElementType*) ::juce_malloc (newNumElements * elementSize); + } + + /** Allocates a specified amount of memory and clears it. + This does the same job as the malloc() method, but clears the memory that it allocates. + */ + void calloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + ::juce_free (data); + data = (ElementType*) ::juce_calloc (newNumElements * elementSize); + } + + /** Allocates a specified amount of memory and optionally clears it. + This does the same job as either malloc() or calloc(), depending on the + initialiseToZero parameter. + */ + void allocate (const int newNumElements, const bool initialiseToZero) + { + ::juce_free (data); + + if (initialiseToZero) + data = (ElementType*) ::juce_calloc (newNumElements * sizeof (ElementType)); + else + data = (ElementType*) ::juce_malloc (newNumElements * sizeof (ElementType)); + } + + /** Re-allocates a specified amount of memory. + + The semantics of this method are the same as malloc() and calloc(), but it + uses realloc() to keep as much of the existing data as possible. + */ + void realloc (const int newNumElements, const unsigned int elementSize = sizeof (ElementType)) + { + if (data == 0) + data = (ElementType*) ::juce_malloc (newNumElements * elementSize); + else + data = (ElementType*) ::juce_realloc (data, newNumElements * elementSize); + } + + /** Frees any currently-allocated data. + This will free the data and reset this object to be a null pointer. + */ + void free() + { + ::juce_free (data); + data = 0; + } + + /** Swaps this object's data with the data of another HeapBlock. + The two objects simply exchange their data pointers. + */ + void swapWith (HeapBlock & other) + { + swapVariables (data, other.data); + } + + +private: + //============================================================================== + ElementType* data; + + HeapBlock (const HeapBlock&); + const HeapBlock& operator= (const HeapBlock&); +}; + + +#endif // __JUCE_HEAPBLOCK_JUCEHEADER__ diff --git a/src/containers/juce_MemoryBlock.cpp b/src/containers/juce_MemoryBlock.cpp index 3b92bce1cf..5541adf0f6 100644 --- a/src/containers/juce_MemoryBlock.cpp +++ b/src/containers/juce_MemoryBlock.cpp @@ -32,8 +32,7 @@ BEGIN_JUCE_NAMESPACE //============================================================================== MemoryBlock::MemoryBlock() throw() - : data (0), - size (0) + : size (0) { } @@ -43,35 +42,28 @@ MemoryBlock::MemoryBlock (const int initialSize, if (initialSize > 0) { size = initialSize; - - if (initialiseToZero) - data = (char*) juce_calloc (initialSize); - else - data = (char*) juce_malloc (initialSize); + data.allocate (initialSize, initialiseToZero); } else { - data = 0; size = 0; } } MemoryBlock::MemoryBlock (const MemoryBlock& other) throw() - : data (0), - size (other.size) + : size (other.size) { if (size > 0) { jassert (other.data != 0); - data = (char*) juce_malloc (size); + data.malloc (size); memcpy (data, other.data, size); } } MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const int sizeInBytes) throw() - : data (0), - size (jmax (0, sizeInBytes)) + : size (jmax (0, sizeInBytes)) { jassert (sizeInBytes >= 0); @@ -79,7 +71,7 @@ MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, { jassert (dataToInitialiseFrom != 0); // non-zero size, but a zero pointer passed-in? - data = (char*) juce_malloc (size); + data.malloc (size); if (dataToInitialiseFrom != 0) memcpy (data, dataToInitialiseFrom, size); @@ -90,8 +82,6 @@ MemoryBlock::~MemoryBlock() throw() { jassert (size >= 0); // should never happen jassert (size == 0 || data != 0); // non-zero size but no data allocated? - - juce_free (data); } const MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw() @@ -126,25 +116,21 @@ void MemoryBlock::setSize (const int newSize, { if (newSize <= 0) { - juce_free (data); - data = 0; + data.free(); size = 0; } else { if (data != 0) { - data = (char*) juce_realloc (data, newSize); + data.realloc (newSize); if (initialiseToZero && (newSize > size)) zeromem (data + size, newSize - size); } else { - if (initialiseToZero) - data = (char*) juce_calloc (newSize); - else - data = (char*) juce_malloc (newSize); + data.allocate (newSize, initialiseToZero); } size = newSize; @@ -242,7 +228,7 @@ void MemoryBlock::removeSection (int startByte, int numBytesToRemove) throw() const String MemoryBlock::toString() const throw() { - return String (data, size); + return String ((const char*) data, size); } //============================================================================== diff --git a/src/containers/juce_MemoryBlock.h b/src/containers/juce_MemoryBlock.h index 068766cdd9..e3f63f05e4 100644 --- a/src/containers/juce_MemoryBlock.h +++ b/src/containers/juce_MemoryBlock.h @@ -27,6 +27,7 @@ #define __JUCE_MEMORYBLOCK_JUCEHEADER__ #include "../text/juce_String.h" +#include "juce_HeapBlock.h" //============================================================================== @@ -232,7 +233,7 @@ public: private: //============================================================================== - char* data; + HeapBlock data; int size; }; diff --git a/src/containers/juce_Variant.cpp b/src/containers/juce_Variant.cpp index b0cd527ffe..ac2ca73231 100644 --- a/src/containers/juce_Variant.cpp +++ b/src/containers/juce_Variant.cpp @@ -318,10 +318,9 @@ void var::writeToStream (OutputStream& output) const throw() const int len = value.stringValue->copyToUTF8 (0); output.writeCompressedInt (len + 1); output.writeByte (5); - uint8* const temp = (uint8*) juce_malloc (len); + HeapBlock temp (len); value.stringValue->copyToUTF8 (temp); output.write (temp, len); - juce_free (temp); break; } case objectType: output.writeCompressedInt (0); jassertfalse; break; // Can't write an object to a stream! diff --git a/src/containers/juce_Variant.h b/src/containers/juce_Variant.h index ea6b5ae31d..61baf0baf7 100644 --- a/src/containers/juce_Variant.h +++ b/src/containers/juce_Variant.h @@ -29,6 +29,7 @@ #include "juce_ReferenceCountedObject.h" #include "juce_OwnedArray.h" #include "../text/juce_StringArray.h" +#include "../containers/juce_Array.h" #include "../io/streams/juce_OutputStream.h" #include "../io/streams/juce_InputStream.h" diff --git a/src/core/juce_Memory.h b/src/core/juce_Memory.h index 88e875216f..80beee2bd7 100644 --- a/src/core/juce_Memory.h +++ b/src/core/juce_Memory.h @@ -37,13 +37,24 @@ //============================================================================== // Win32 debug non-DLL versions.. - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) _malloc_dbg (numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) _calloc_dbg (1, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) _realloc_dbg (location, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) _free_dbg (location, _NORMAL_BLOCK) #else @@ -57,13 +68,24 @@ extern JUCE_API void* juce_DebugRealloc (void* const block, const int size, const char* file, const int line); extern JUCE_API void juce_DebugFree (void* const block); - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_DebugMalloc (numBytes, __FILE__, __LINE__) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_DebugCalloc (numBytes, __FILE__, __LINE__) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_DebugRealloc (location, numBytes, __FILE__, __LINE__) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) JUCE_NAMESPACE::juce_DebugFree (location) #endif @@ -89,13 +111,24 @@ extern JUCE_API void* juce_Realloc (void* const block, const int size); extern JUCE_API void juce_Free (void* const block); - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_Malloc (numBytes) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_Calloc (numBytes) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_Realloc (location, numBytes) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) JUCE_NAMESPACE::juce_Free (location) #define juce_UseDebuggingNewOperator \ @@ -108,13 +141,24 @@ //============================================================================== // Mac, Linux and Win32 (release) versions.. - /** This should be used instead of calling malloc directly. */ + /** This should be used instead of calling malloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_malloc(numBytes) malloc (numBytes) - /** This should be used instead of calling calloc directly. */ + + /** This should be used instead of calling calloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_calloc(numBytes) calloc (1, numBytes) - /** This should be used instead of calling realloc directly. */ + + /** This should be used instead of calling realloc directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_realloc(location, numBytes) realloc (location, numBytes) - /** This should be used instead of calling free directly. */ + + /** This should be used instead of calling free directly. + Only use direct memory allocation if there's really no way to use a HeapBlock object instead! + */ #define juce_free(location) free (location) #endif diff --git a/src/cryptography/juce_BlowFish.cpp b/src/cryptography/juce_BlowFish.cpp index f5ba6ef7b5..c787eeab41 100644 --- a/src/cryptography/juce_BlowFish.cpp +++ b/src/cryptography/juce_BlowFish.cpp @@ -309,7 +309,7 @@ BlowFish::BlowFish (const uint8* keyData, int keyBytes) int i, j; for (i = 4; --i >= 0;) { - s[i] = (uint32*) juce_malloc (256 * sizeof (uint32)); + s[i].malloc (256); memcpy (s[i], initialSValues + i * 256, 256 * sizeof (uint32)); } @@ -355,7 +355,7 @@ BlowFish::BlowFish (const uint8* keyData, int keyBytes) BlowFish::BlowFish (const BlowFish& other) { for (int i = 4; --i >= 0;) - s[i] = (uint32*) juce_malloc (256 * sizeof (uint32)); + s[i].malloc (256); operator= (other); } @@ -372,8 +372,6 @@ const BlowFish& BlowFish::operator= (const BlowFish& other) BlowFish::~BlowFish() { - for (int i = 4; --i >= 0;) - juce_free (s[i]); } uint32 BlowFish::F (uint32 x) const diff --git a/src/cryptography/juce_BlowFish.h b/src/cryptography/juce_BlowFish.h index a2fbf4cb63..eaa8d03641 100644 --- a/src/cryptography/juce_BlowFish.h +++ b/src/cryptography/juce_BlowFish.h @@ -26,6 +26,8 @@ #ifndef __JUCE_BLOWFISH_JUCEHEADER__ #define __JUCE_BLOWFISH_JUCEHEADER__ +#include "../containers/juce_HeapBlock.h" + //============================================================================== /** @@ -64,7 +66,7 @@ public: private: uint32 p[18]; - uint32* s[4]; + HeapBlock s[4]; uint32 F (uint32 x) const; }; diff --git a/src/gui/components/code_editor/juce_CodeDocument.h b/src/gui/components/code_editor/juce_CodeDocument.h index f849d63431..1ed189354d 100644 --- a/src/gui/components/code_editor/juce_CodeDocument.h +++ b/src/gui/components/code_editor/juce_CodeDocument.h @@ -28,6 +28,7 @@ #include "../../../utilities/juce_UndoManager.h" #include "../../graphics/colour/juce_Colour.h" +#include "../../../containers/juce_VoidArray.h" class CodeDocumentLine; diff --git a/src/gui/components/special/juce_MidiKeyboardComponent.cpp b/src/gui/components/special/juce_MidiKeyboardComponent.cpp index 95657c1799..0c2bba990f 100644 --- a/src/gui/components/special/juce_MidiKeyboardComponent.cpp +++ b/src/gui/components/special/juce_MidiKeyboardComponent.cpp @@ -702,7 +702,7 @@ void MidiKeyboardComponent::resetAnyKeysInUse() void MidiKeyboardComponent::updateNoteUnderMouse (int x, int y) { - float mousePositionVelocity; + float mousePositionVelocity = 0.0f; const int newNote = (mouseDragging || isMouseOver()) ? xyToNote (x, y, mousePositionVelocity) : -1; diff --git a/src/gui/graphics/colour/juce_ColourGradient.cpp b/src/gui/graphics/colour/juce_ColourGradient.cpp index 127756c4ac..eebf6881df 100644 --- a/src/gui/graphics/colour/juce_ColourGradient.cpp +++ b/src/gui/graphics/colour/juce_ColourGradient.cpp @@ -138,7 +138,7 @@ const Colour ColourGradient::getColourAtPosition (const float position) const th } //============================================================================== -PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, int& numEntries) const throw() +int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock & lookupTable) const throw() { #ifdef JUCE_DEBUG // trying to use the object without setting its co-ordinates? Have a careful read of @@ -153,9 +153,8 @@ PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, transform.transformPoint (tx2, ty2); const double distance = juce_hypot (tx1 - tx2, ty1 - ty2); - numEntries = jlimit (1, (numColours - 1) << 8, 3 * (int) distance); - - PixelARGB* const lookupTable = (PixelARGB*) juce_calloc (numEntries * sizeof (PixelARGB)); + const int numEntries = jlimit (1, (numColours - 1) << 8, 3 * (int) distance); + lookupTable.malloc (numEntries); if (numColours >= 2) { @@ -191,7 +190,7 @@ PixelARGB* ColourGradient::createLookupTable (const AffineTransform& transform, jassertfalse // no colours specified! } - return lookupTable; + return numEntries; } bool ColourGradient::isOpaque() const throw() diff --git a/src/gui/graphics/colour/juce_ColourGradient.h b/src/gui/graphics/colour/juce_ColourGradient.h index 711d53a59c..95cf6b406b 100644 --- a/src/gui/graphics/colour/juce_ColourGradient.h +++ b/src/gui/graphics/colour/juce_ColourGradient.h @@ -29,6 +29,7 @@ #include "juce_Colour.h" #include "../geometry/juce_AffineTransform.h" #include "../../../containers/juce_Array.h" +#include "../../../containers/juce_HeapBlock.h" //============================================================================== @@ -123,10 +124,10 @@ public: //============================================================================== /** Creates a set of interpolated premultiplied ARGB values. - - The caller must delete the array that is returned using juce_free(). + This will resize the HeapBlock, fill it with the colours, and will return the number of + colours that it added. */ - PixelARGB* createLookupTable (const AffineTransform& transform, int& numEntries) const throw(); + int createLookupTable (const AffineTransform& transform, HeapBlock & resultLookupTable) const throw(); /** Returns true if all colours are opaque. */ bool isOpaque() const throw(); diff --git a/src/gui/graphics/contexts/juce_EdgeTable.cpp b/src/gui/graphics/contexts/juce_EdgeTable.cpp index 66ba68bce8..4bc4ac9efa 100644 --- a/src/gui/graphics/contexts/juce_EdgeTable.cpp +++ b/src/gui/graphics/contexts/juce_EdgeTable.cpp @@ -53,7 +53,7 @@ EdgeTable::EdgeTable (const Rectangle& bounds_, lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), needToCheckEmptinesss (true) { - table = (int*) juce_malloc ((bounds.getHeight() + 1) * lineStrideElements * sizeof (int)); + table.malloc ((bounds.getHeight() + 1) * lineStrideElements); int* t = table; for (int i = bounds.getHeight(); --i >= 0;) @@ -127,8 +127,8 @@ EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), needToCheckEmptinesss (true) { - table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); - *table = 0; + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); + table[0] = 0; const int x1 = rectangleToAdd.getX() << 8; const int x2 = rectangleToAdd.getRight() << 8; @@ -151,7 +151,7 @@ EdgeTable::EdgeTable (const RectangleList& rectanglesToAdd) throw() lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), needToCheckEmptinesss (true) { - table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); int* t = table; for (int i = bounds.getHeight(); --i >= 0;) @@ -186,8 +186,8 @@ EdgeTable::EdgeTable (const float x, const float y, const float w, const float h needToCheckEmptinesss (true) { jassert (w > 0 && h > 0); - table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); - *table = 0; + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); + table[0] = 0; const int x1 = roundFloatToInt (x * 256.0f); const int x2 = roundFloatToInt ((x + w) * 256.0f); @@ -262,22 +262,18 @@ EdgeTable::EdgeTable (const EdgeTable& other) throw() const EdgeTable& EdgeTable::operator= (const EdgeTable& other) throw() { - juce_free (table); - bounds = other.bounds; maxEdgesPerLine = other.maxEdgesPerLine; lineStrideElements = other.lineStrideElements; needToCheckEmptinesss = other.needToCheckEmptinesss; - const int tableSize = jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int); - table = (int*) juce_malloc (tableSize); + table.malloc (jmax (1, bounds.getHeight()) * lineStrideElements); copyEdgeTableData (table, lineStrideElements, other.table, lineStrideElements, bounds.getHeight()); return *this; } EdgeTable::~EdgeTable() throw() { - juce_free (table); } //============================================================================== @@ -340,12 +336,12 @@ void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) throw() jassert (bounds.getHeight() > 0); const int newLineStrideElements = maxEdgesPerLine * 2 + 1; - int* const newTable = (int*) juce_malloc (bounds.getHeight() * newLineStrideElements * sizeof (int)); + + HeapBlock newTable (bounds.getHeight() * newLineStrideElements); copyEdgeTableData (newTable, newLineStrideElements, table, lineStrideElements, bounds.getHeight()); - juce_free (table); - table = newTable; + table.swapWith (newTable); lineStrideElements = newLineStrideElements; } } diff --git a/src/gui/graphics/contexts/juce_EdgeTable.h b/src/gui/graphics/contexts/juce_EdgeTable.h index 6a5e5a42a0..9787009799 100644 --- a/src/gui/graphics/contexts/juce_EdgeTable.h +++ b/src/gui/graphics/contexts/juce_EdgeTable.h @@ -195,7 +195,7 @@ public: private: // table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc - int* table; + HeapBlock table; Rectangle bounds; int maxEdgesPerLine, lineStrideElements; bool needToCheckEmptinesss; diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index a6a3368791..a3862a262d 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -41,13 +41,13 @@ BEGIN_JUCE_NAMESPACE #define JUCE_USE_SSE_INSTRUCTIONS 1 #endif +#if JUCE_MSVC && JUCE_DEBUG + #pragma warning (disable: 4714) // warning about forcedinline methods not being inlined +#endif + #if JUCE_MSVC #pragma warning (push) #pragma warning (disable: 4127) // "expression is constant" warning - - #if JUCE_DEBUG - #pragma warning (disable: 4714) // warning about forcedinline methods not being inlined - #endif #endif //============================================================================== @@ -520,12 +520,11 @@ public: maxY (srcData_.height - 1), scratchSize (2048) { - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } ~TransformedImageFillEdgeTableRenderer() throw() { - juce_free (scratchBuffer); } forcedinline void setEdgeTableYPos (const int newY) throw() @@ -550,8 +549,7 @@ public: if (width > scratchSize) { scratchSize = width; - juce_free (scratchBuffer); - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } SrcPixelType* span = scratchBuffer; @@ -582,8 +580,7 @@ public: if (width > scratchSize) { scratchSize = width; - juce_free (scratchBuffer); - scratchBuffer = (SrcPixelType*) juce_malloc (scratchSize * sizeof (SrcPixelType)); + scratchBuffer.malloc (scratchSize); } uint8* mask = (uint8*) scratchBuffer; @@ -893,7 +890,7 @@ private: const int pixelOffsetInt, maxX, maxY; int y; DestPixelType* linePixels; - SrcPixelType* scratchBuffer; + HeapBlock scratchBuffer; int scratchSize; TransformedImageFillEdgeTableRenderer (const TransformedImageFillEdgeTableRenderer&); @@ -983,8 +980,8 @@ public: transform = AffineTransform::identity; } - int numLookupEntries; - PixelARGB* const lookupTable = g2.createLookupTable (transform, numLookupEntries); + HeapBlock lookupTable; + const int numLookupEntries = g2.createLookupTable (transform, lookupTable); jassert (numLookupEntries > 0); switch (image.getFormat()) @@ -993,8 +990,6 @@ public: case Image::RGB: renderGradient (et, destData, g2, transform, lookupTable, numLookupEntries, isIdentity, (PixelRGB*) 0); break; default: renderGradient (et, destData, g2, transform, lookupTable, numLookupEntries, isIdentity, (PixelAlpha*) 0); break; } - - juce_free (lookupTable); } else if (fillType.isTiledImage()) { diff --git a/src/gui/graphics/fonts/juce_TextLayout.h b/src/gui/graphics/fonts/juce_TextLayout.h index bb83347c7e..b5f8ff4d27 100644 --- a/src/gui/graphics/fonts/juce_TextLayout.h +++ b/src/gui/graphics/fonts/juce_TextLayout.h @@ -28,6 +28,7 @@ #include "juce_Font.h" #include "../contexts/juce_Justification.h" +#include "../../../containers/juce_VoidArray.h" class Graphics; diff --git a/src/gui/graphics/geometry/juce_PathIterator.cpp b/src/gui/graphics/geometry/juce_PathIterator.cpp index f3e34be5e3..f943408ada 100644 --- a/src/gui/graphics/geometry/juce_PathIterator.cpp +++ b/src/gui/graphics/geometry/juce_PathIterator.cpp @@ -48,17 +48,16 @@ PathFlatteningIterator::PathFlatteningIterator (const Path& path_, tolerence (tolerence_ * tolerence_), subPathCloseX (0), subPathCloseY (0), + stackBase (32), index (0), stackSize (32) { - stackBase = (float*) juce_malloc (stackSize * sizeof (float)); isIdentityTransform = transform.isIdentity(); stackPos = stackBase; } PathFlatteningIterator::~PathFlatteningIterator() throw() { - juce_free (stackBase); } bool PathFlatteningIterator::next() throw() @@ -159,7 +158,7 @@ bool PathFlatteningIterator::next() throw() if (offset >= stackSize - 10) { stackSize <<= 1; - stackBase = (float*) juce_realloc (stackBase, stackSize * sizeof (float)); + stackBase.realloc (stackSize); stackPos = stackBase + offset; } @@ -209,7 +208,7 @@ bool PathFlatteningIterator::next() throw() if (offset >= stackSize - 16) { stackSize <<= 1; - stackBase = (float*) juce_realloc (stackBase, stackSize * sizeof (float)); + stackBase.realloc (stackSize); stackPos = stackBase + offset; } diff --git a/src/gui/graphics/geometry/juce_PathIterator.h b/src/gui/graphics/geometry/juce_PathIterator.h index 045f34068d..7ea8b17811 100644 --- a/src/gui/graphics/geometry/juce_PathIterator.h +++ b/src/gui/graphics/geometry/juce_PathIterator.h @@ -110,7 +110,7 @@ private: float tolerence, subPathCloseX, subPathCloseY; bool isIdentityTransform; - float* stackBase; + HeapBlock stackBase; float* stackPos; int index, stackSize; diff --git a/src/gui/graphics/geometry/juce_PathStrokeType.cpp b/src/gui/graphics/geometry/juce_PathStrokeType.cpp index deece0c8be..1add4db0eb 100644 --- a/src/gui/graphics/geometry/juce_PathStrokeType.cpp +++ b/src/gui/graphics/geometry/juce_PathStrokeType.cpp @@ -30,7 +30,6 @@ BEGIN_JUCE_NAMESPACE #include "juce_PathStrokeType.h" #include "juce_PathIterator.h" -#include "../../../containers/juce_VoidArray.h" //============================================================================== diff --git a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp index bcaa9434c7..9834323135 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_JPEGLoader.cpp @@ -326,7 +326,8 @@ bool juce_writeJPEGImageToStream (const Image& image, jpegCompStruct.dest = &dest; dest.output = &out; - dest.buffer = (char*) juce_malloc (bufferSize); + HeapBlock tempBuffer (bufferSize); + dest.buffer = (char*) tempBuffer; dest.next_output_byte = (JOCTET*) dest.buffer; dest.free_in_buffer = bufferSize; dest.init_destination = jpegWriteInit; @@ -382,8 +383,6 @@ bool juce_writeJPEGImageToStream (const Image& image, jpeg_finish_compress (&jpegCompStruct); jpeg_destroy_compress (&jpegCompStruct); - juce_free (dest.buffer); - out.flush(); return true; diff --git a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp index 9b85437d1e..196ebda450 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_PNGLoader.cpp @@ -178,17 +178,17 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() || pngInfoStruct->num_trans > 0; // Load the image into a temp buffer in the pnglib format.. - uint8* const tempBuffer = (uint8*) juce_malloc (height * (width << 2)); + HeapBlock tempBuffer (height * (width << 2)); - png_bytepp rows = (png_bytepp) juce_malloc (sizeof (png_bytep) * height); - int y; - for (y = (int) height; --y >= 0;) - rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); + { + HeapBlock rows (height); + for (int y = (int) height; --y >= 0;) + rows[y] = (png_bytep) (tempBuffer + (width << 2) * y); - png_read_image (pngReadStruct, rows); - png_read_end (pngReadStruct, pngInfoStruct); + png_read_image (pngReadStruct, rows); + png_read_end (pngReadStruct, pngInfoStruct); + } - juce_free (rows); png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); // now convert the data to a juce image format.. @@ -201,7 +201,7 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() uint8* srcRow = tempBuffer; uint8* destRow = destData.data; - for (y = 0; y < (int) height; ++y) + for (int y = 0; y < (int) height; ++y) { const uint8* src = srcRow; srcRow += (width << 2); @@ -228,8 +228,6 @@ Image* juce_loadPNGImageFromStream (InputStream& in) throw() } } } - - juce_free (tempBuffer); } return image; @@ -273,7 +271,7 @@ bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_bytep rowData = (png_bytep) juce_malloc (width * 4 * sizeof (png_byte)); + HeapBlock rowData (width * 4); png_color_8 sig_bit; sig_bit.red = 8; @@ -322,8 +320,6 @@ bool juce_writePNGImageToStream (const Image& image, OutputStream& out) throw() png_write_rows (pngWriteStruct, &rowData, 1); } - juce_free (rowData); - png_write_end (pngWriteStruct, pngInfoStruct); png_destroy_write_struct (&pngWriteStruct, &pngInfoStruct); diff --git a/src/gui/graphics/imaging/juce_Image.cpp b/src/gui/graphics/imaging/juce_Image.cpp index d9ccd024ea..1b50f5a594 100644 --- a/src/gui/graphics/imaging/juce_Image.cpp +++ b/src/gui/graphics/imaging/juce_Image.cpp @@ -65,10 +65,9 @@ Image::Image (const PixelFormat format_, pixelStride = (format == RGB) ? 3 : ((format == ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, imageWidth_) + 3) & ~3; - const int dataSize = lineStride * jmax (1, imageHeight_); - imageData = (uint8*) (clearImage ? juce_calloc (dataSize) - : juce_malloc (dataSize)); + imageDataAllocated.allocate (lineStride * jmax (1, imageHeight_), clearImage); + imageData = imageDataAllocated; } Image::Image (const Image& other) @@ -78,9 +77,9 @@ Image::Image (const Image& other) { pixelStride = (format == RGB) ? 3 : ((format == ARGB) ? 4 : 1); lineStride = (pixelStride * jmax (1, imageWidth) + 3) & ~3; - const int dataSize = lineStride * jmax (1, imageHeight); - imageData = (uint8*) juce_malloc (dataSize); + imageDataAllocated.malloc (lineStride * jmax (1, imageHeight)); + imageData = imageDataAllocated; BitmapData srcData (other, 0, 0, imageWidth, imageHeight); setPixelData (0, 0, imageWidth, imageHeight, srcData.data, srcData.lineStride); @@ -88,7 +87,6 @@ Image::Image (const Image& other) Image::~Image() { - juce_free (imageData); } //============================================================================== diff --git a/src/gui/graphics/imaging/juce_Image.h b/src/gui/graphics/imaging/juce_Image.h index 48ff1c94ed..8239686469 100644 --- a/src/gui/graphics/imaging/juce_Image.h +++ b/src/gui/graphics/imaging/juce_Image.h @@ -291,9 +291,9 @@ protected: const int imageHeight); int pixelStride, lineStride; + HeapBlock imageDataAllocated; uint8* imageData; - private: //============================================================================== const Image& operator= (const Image&); diff --git a/src/gui/graphics/imaging/juce_ImageCache.h b/src/gui/graphics/imaging/juce_ImageCache.h index a3c1e7a5b9..8937e84ff9 100644 --- a/src/gui/graphics/imaging/juce_ImageCache.h +++ b/src/gui/graphics/imaging/juce_ImageCache.h @@ -30,6 +30,7 @@ #include "../../../io/files/juce_File.h" #include "../../../events/juce_Timer.h" #include "../../../utilities/juce_DeletedAtShutdown.h" +#include "../../../containers/juce_VoidArray.h" //============================================================================== diff --git a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp index 1550174b4f..1e9690d0b4 100644 --- a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp +++ b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.cpp @@ -32,22 +32,14 @@ BEGIN_JUCE_NAMESPACE //============================================================================== ImageConvolutionKernel::ImageConvolutionKernel (const int size_) throw() - : size (size_) + : values (size_ * size_), + size (size_) { - values = new float* [size]; - - for (int i = size; --i >= 0;) - values[i] = new float [size]; - clear(); } ImageConvolutionKernel::~ImageConvolutionKernel() throw() { - for (int i = size; --i >= 0;) - delete[] values[i]; - - delete[] values; } //============================================================================== @@ -58,7 +50,7 @@ void ImageConvolutionKernel::setKernelValue (const int x, if (((unsigned int) x) < (unsigned int) size && ((unsigned int) y) < (unsigned int) size) { - values[x][y] = value; + values [x + y * size] = value; } else { @@ -68,27 +60,24 @@ void ImageConvolutionKernel::setKernelValue (const int x, void ImageConvolutionKernel::clear() throw() { - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - values[x][y] = 0; + for (int i = size * size; --i >= 0;) + values[i] = 0; } void ImageConvolutionKernel::setOverallSum (const float desiredTotalSum) throw() { double currentTotal = 0.0; - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - currentTotal += values[x][y]; + for (int i = size * size; --i >= 0;) + currentTotal += values[i]; rescaleAllValues ((float) (desiredTotalSum / currentTotal)); } void ImageConvolutionKernel::rescaleAllValues (const float multiplier) throw() { - for (int y = size; --y >= 0;) - for (int x = size; --x >= 0;) - values[x][y] *= multiplier; + for (int i = size * size; --i >= 0;) + values[i] *= multiplier; } //============================================================================== @@ -104,7 +93,7 @@ void ImageConvolutionKernel::createGaussianBlur (const float radius) throw() const int cx = x - centre; const int cy = y - centre; - values[x][y] = (float) exp (radiusFactor * (cx * cx + cy * cy)); + values [x + y * size] = (float) exp (radiusFactor * (cx * cx + cy * cy)); } } @@ -190,7 +179,7 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, if (sx >= 0) { - const float kernelMult = values[xx][yy]; + const float kernelMult = values [xx + yy * size]; c1 += kernelMult * *src++; c2 += kernelMult * *src++; c3 += kernelMult * *src++; @@ -245,7 +234,7 @@ void ImageConvolutionKernel::applyToImage (Image& destImage, if (sx >= 0) { - const float kernelMult = values[xx][yy]; + const float kernelMult = values [xx + yy * size]; c1 += kernelMult * *src++; c2 += kernelMult * *src++; c3 += kernelMult * *src++; diff --git a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.h b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.h index b5eb37b21c..65f6e24797 100644 --- a/src/gui/graphics/imaging/juce_ImageConvolutionKernel.h +++ b/src/gui/graphics/imaging/juce_ImageConvolutionKernel.h @@ -119,8 +119,8 @@ public: juce_UseDebuggingNewOperator private: - float** values; - int size; + HeapBlock values; + const int size; // no reason not to implement these one day.. ImageConvolutionKernel (const ImageConvolutionKernel&); diff --git a/src/io/files/juce_FileOutputStream.cpp b/src/io/files/juce_FileOutputStream.cpp index 15d65a07ea..9bfa20bf4f 100644 --- a/src/io/files/juce_FileOutputStream.cpp +++ b/src/io/files/juce_FileOutputStream.cpp @@ -58,7 +58,7 @@ FileOutputStream::FileOutputStream (const File& f, } } - buffer = (char*) juce_malloc (jmax (bufferSize_, 16)); + buffer.malloc (jmax (bufferSize_, 16)); } FileOutputStream::~FileOutputStream() @@ -66,7 +66,6 @@ FileOutputStream::~FileOutputStream() flush(); juce_fileClose (fileHandle); - juce_free (buffer); } int64 FileOutputStream::getPosition() diff --git a/src/io/files/juce_FileOutputStream.h b/src/io/files/juce_FileOutputStream.h index fffa35b187..56f24633e1 100644 --- a/src/io/files/juce_FileOutputStream.h +++ b/src/io/files/juce_FileOutputStream.h @@ -84,7 +84,7 @@ private: void* fileHandle; int64 currentPosition; int bufferSize, bytesInBuffer; - char* buffer; + HeapBlock buffer; }; #endif // __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ diff --git a/src/io/files/juce_ZipFile.h b/src/io/files/juce_ZipFile.h index f54b688bde..11d4f54e0c 100644 --- a/src/io/files/juce_ZipFile.h +++ b/src/io/files/juce_ZipFile.h @@ -30,6 +30,7 @@ #include "../streams/juce_InputStream.h" #include "../streams/juce_InputSource.h" #include "../../threads/juce_CriticalSection.h" +#include "../../containers/juce_VoidArray.h" //============================================================================== diff --git a/src/io/network/juce_URL.cpp b/src/io/network/juce_URL.cpp index 2728204530..3f4914bdf6 100644 --- a/src/io/network/juce_URL.cpp +++ b/src/io/network/juce_URL.cpp @@ -550,7 +550,7 @@ const StringPairArray& URL::getMimeTypesOfUploadFiles() const throw() const String URL::removeEscapeChars (const String& s) { const int len = s.length(); - uint8* const resultUTF8 = (uint8*) juce_calloc (len * 4); + HeapBlock resultUTF8 (len * 4); uint8* r = resultUTF8; for (int i = 0; i < len; ++i) @@ -572,9 +572,7 @@ const String URL::removeEscapeChars (const String& s) *r++ = c; } - const String stringResult (String::fromUTF8 (resultUTF8)); - juce_free (resultUTF8); - return stringResult; + return String::fromUTF8 (resultUTF8); } const String URL::addEscapeChars (const String& s, const bool isParameter) diff --git a/src/io/streams/juce_BufferedInputStream.cpp b/src/io/streams/juce_BufferedInputStream.cpp index 3d477cb338..6563611731 100644 --- a/src/io/streams/juce_BufferedInputStream.cpp +++ b/src/io/streams/juce_BufferedInputStream.cpp @@ -47,15 +47,13 @@ BufferedInputStream::BufferedInputStream (InputStream* const source_, bufferSize = jmin (jmax (32, sourceSize), bufferSize); bufferStart = position; - buffer = (char*) juce_malloc (bufferSize); + buffer.malloc (bufferSize); } BufferedInputStream::~BufferedInputStream() throw() { if (deleteSourceWhenDestroyed) delete source; - - juce_free (buffer); } //============================================================================== @@ -94,7 +92,7 @@ void BufferedInputStream::ensureBuffered() && position >= bufferStart) { const int bytesToKeep = (int) (lastReadPos - position); - memmove (buffer, buffer + position - bufferStart, bytesToKeep); + memmove (buffer, buffer + (int) (position - bufferStart), bytesToKeep); bufferStart = position; @@ -122,7 +120,7 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) if (position >= bufferStart && position + maxBytesToRead <= lastReadPos) { - memcpy (destBuffer, buffer + (position - bufferStart), maxBytesToRead); + memcpy (destBuffer, buffer + (int) (position - bufferStart), maxBytesToRead); position += maxBytesToRead; return maxBytesToRead; @@ -140,7 +138,7 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) if (bytesAvailable > 0) { - memcpy (destBuffer, buffer + (position - bufferStart), bytesAvailable); + memcpy (destBuffer, buffer + (int) (position - bufferStart), bytesAvailable); maxBytesToRead -= bytesAvailable; bytesRead += bytesAvailable; position += bytesAvailable; @@ -168,7 +166,7 @@ const String BufferedInputStream::readString() { const int maxChars = (int) (lastReadPos - position); - const char* const src = buffer + (position - bufferStart); + const char* const src = buffer + (int) (position - bufferStart); for (int i = 0; i < maxChars; ++i) { diff --git a/src/io/streams/juce_BufferedInputStream.h b/src/io/streams/juce_BufferedInputStream.h index b0acde494c..64dc8c22af 100644 --- a/src/io/streams/juce_BufferedInputStream.h +++ b/src/io/streams/juce_BufferedInputStream.h @@ -77,7 +77,7 @@ private: const bool deleteSourceWhenDestroyed; int bufferSize; int64 position, lastReadPos, bufferStart, bufferOverlap; - char* buffer; + HeapBlock buffer; void ensureBuffered(); BufferedInputStream (const BufferedInputStream&); diff --git a/src/io/streams/juce_GZIPCompressorOutputStream.cpp b/src/io/streams/juce_GZIPCompressorOutputStream.cpp index 88c180f5f4..4ed01774e7 100644 --- a/src/io/streams/juce_GZIPCompressorOutputStream.cpp +++ b/src/io/streams/juce_GZIPCompressorOutputStream.cpp @@ -49,7 +49,7 @@ using namespace zlibNamespace; class GZIPCompressorHelper { private: - z_stream* stream; + HeapBlock stream; uint8* data; int dataSize, compLevel, strategy; bool setParams; @@ -66,7 +66,7 @@ public: finished (false), shouldFinish (false) { - stream = (z_stream*) juce_calloc (sizeof (z_stream)); + stream.calloc (1); if (deflateInit2 (stream, compLevel, @@ -75,18 +75,14 @@ public: 8, strategy) != Z_OK) { - juce_free (stream); - stream = 0; + stream.free(); } } ~GZIPCompressorHelper() { if (stream != 0) - { deflateEnd (stream); - juce_free (stream); - } } bool needsInput() const throw() @@ -143,14 +139,14 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest const bool deleteDestStream_, const bool noWrap) : destStream (destStream_), - deleteDestStream (deleteDestStream_) + deleteDestStream (deleteDestStream_), + buffer (gzipCompBufferSize) { if (compressionLevel < 1 || compressionLevel > 9) compressionLevel = -1; helper = new GZIPCompressorHelper (compressionLevel, noWrap); - buffer = (uint8*) juce_malloc (gzipCompBufferSize); } GZIPCompressorOutputStream::~GZIPCompressorOutputStream() @@ -160,8 +156,6 @@ GZIPCompressorOutputStream::~GZIPCompressorOutputStream() GZIPCompressorHelper* const h = (GZIPCompressorHelper*) helper; delete h; - juce_free (buffer); - if (deleteDestStream) delete destStream; } diff --git a/src/io/streams/juce_GZIPCompressorOutputStream.h b/src/io/streams/juce_GZIPCompressorOutputStream.h index 50a3e62cb4..dad214ba61 100644 --- a/src/io/streams/juce_GZIPCompressorOutputStream.h +++ b/src/io/streams/juce_GZIPCompressorOutputStream.h @@ -73,7 +73,7 @@ public: private: OutputStream* const destStream; const bool deleteDestStream; - uint8* buffer; + HeapBlock buffer; void* helper; bool doNextBlock(); diff --git a/src/io/streams/juce_GZIPDecompressorInputStream.cpp b/src/io/streams/juce_GZIPDecompressorInputStream.cpp index 1f1b159168..160a718d22 100644 --- a/src/io/streams/juce_GZIPDecompressorInputStream.cpp +++ b/src/io/streams/juce_GZIPDecompressorInputStream.cpp @@ -81,7 +81,7 @@ using namespace zlibNamespace; class GZIPDecompressHelper { private: - z_stream* stream; + HeapBlock stream; uint8* data; int dataSize; @@ -95,13 +95,12 @@ public: needsDictionary (false), error (false) { - stream = (z_stream*) juce_calloc (sizeof (z_stream)); + stream.calloc (1); if (inflateInit2 (stream, (noWrap) ? -MAX_WBITS : MAX_WBITS) != Z_OK) { - juce_free (stream); - stream = 0; + stream.free(); error = true; finished = true; } @@ -110,10 +109,7 @@ public: ~GZIPDecompressHelper() throw() { if (stream != 0) - { inflateEnd (stream); - juce_free (stream); - } } bool needsInput() const throw() { return dataSize <= 0; } @@ -177,16 +173,14 @@ GZIPDecompressorInputStream::GZIPDecompressorInputStream (InputStream* const sou isEof (false), activeBufferSize (0), originalSourcePos (sourceStream_->getPosition()), - currentPos (0) + currentPos (0), + buffer (gzipDecompBufferSize) { - buffer = (uint8*) juce_malloc (gzipDecompBufferSize); helper = new GZIPDecompressHelper (noWrap_); } GZIPDecompressorInputStream::~GZIPDecompressorInputStream() { - juce_free (buffer); - if (deleteSourceWhenDestroyed) delete sourceStream; diff --git a/src/io/streams/juce_GZIPDecompressorInputStream.h b/src/io/streams/juce_GZIPDecompressorInputStream.h index d2db5ff305..9d16637cdd 100644 --- a/src/io/streams/juce_GZIPDecompressorInputStream.h +++ b/src/io/streams/juce_GZIPDecompressorInputStream.h @@ -80,7 +80,7 @@ private: bool isEof; int activeBufferSize; int64 originalSourcePos, currentPos; - uint8* buffer; + HeapBlock buffer; void* helper; GZIPDecompressorInputStream (const GZIPDecompressorInputStream&); diff --git a/src/io/streams/juce_OutputStream.cpp b/src/io/streams/juce_OutputStream.cpp index 0bb9210e5a..1140d527a9 100644 --- a/src/io/streams/juce_OutputStream.cpp +++ b/src/io/streams/juce_OutputStream.cpp @@ -170,18 +170,16 @@ void OutputStream::writeDoubleBigEndian (double value) void OutputStream::writeString (const String& text) { const int numBytes = text.copyToUTF8 (0); - uint8* const temp = (uint8*) juce_malloc (numBytes); + HeapBlock temp (numBytes); text.copyToUTF8 (temp); write (temp, numBytes); // (numBytes includes the terminating null). - - juce_free (temp); } void OutputStream::printf (const char* pf, ...) { unsigned int bufSize = 256; - char* buf = (char*) juce_malloc (bufSize); + HeapBlock buf (bufSize); for (;;) { @@ -202,12 +200,9 @@ void OutputStream::printf (const char* pf, ...) break; } - juce_free (buf); bufSize += 256; - buf = (char*) juce_malloc (bufSize); + buf.malloc (bufSize); } - - juce_free (buf); } OutputStream& OutputStream::operator<< (const int number) diff --git a/src/juce_app_includes.h b/src/juce_app_includes.h index 668f13c348..9b4b98b7e0 100644 --- a/src/juce_app_includes.h +++ b/src/juce_app_includes.h @@ -44,53 +44,47 @@ #ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ #include "application/juce_ApplicationProperties.h" #endif -#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ - #include "audio/midi/juce_MidiBuffer.h" -#endif -#ifndef __JUCE_MIDIFILE_JUCEHEADER__ - #include "audio/midi/juce_MidiFile.h" -#endif -#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ - #include "audio/midi/juce_MidiKeyboardState.h" +#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AiffAudioFormat.h" #endif -#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ - #include "audio/midi/juce_MidiMessageCollector.h" +#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioCDBurner.h" #endif -#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ - #include "audio/midi/juce_MidiMessageSequence.h" +#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioCDReader.h" #endif -#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ - #include "audio/midi/juce_MidiMessage.h" +#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioFormat.h" #endif -#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ - #include "audio/dsp/juce_AudioDataConverters.h" +#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioFormatManager.h" #endif -#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ - #include "audio/dsp/juce_AudioSampleBuffer.h" +#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioFormatReader.h" #endif -#ifndef __JUCE_IIRFILTER_JUCEHEADER__ - #include "audio/dsp/juce_IIRFilter.h" +#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioFormatWriter.h" #endif -#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ - #include "audio/processors/juce_AudioPlayHead.h" +#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioSubsectionReader.h" #endif -#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ - #include "audio/processors/juce_AudioProcessor.h" +#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioThumbnail.h" #endif -#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ - #include "audio/processors/juce_AudioProcessorEditor.h" +#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ + #include "audio/audio_file_formats/juce_AudioThumbnailCache.h" #endif -#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ - #include "audio/processors/juce_AudioProcessorGraph.h" +#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_FlacAudioFormat.h" #endif -#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ - #include "audio/processors/juce_AudioProcessorListener.h" +#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_OggVorbisAudioFormat.h" #endif -#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ - #include "audio/processors/juce_AudioProcessorPlayer.h" +#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_QuickTimeAudioFormat.h" #endif -#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ - #include "audio/processors/juce_GenericAudioProcessorEditor.h" +#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ + #include "audio/audio_file_formats/juce_WavAudioFormat.h" #endif #ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ #include "audio/audio_sources/juce_AudioFormatReaderSource.h" @@ -140,11 +134,32 @@ #ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ #include "audio/devices/juce_MidiOutput.h" #endif -#ifndef __JUCE_SAMPLER_JUCEHEADER__ - #include "audio/synthesisers/juce_Sampler.h" +#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ + #include "audio/dsp/juce_AudioDataConverters.h" #endif -#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ - #include "audio/synthesisers/juce_Synthesiser.h" +#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ + #include "audio/dsp/juce_AudioSampleBuffer.h" +#endif +#ifndef __JUCE_IIRFILTER_JUCEHEADER__ + #include "audio/dsp/juce_IIRFilter.h" +#endif +#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ + #include "audio/midi/juce_MidiBuffer.h" +#endif +#ifndef __JUCE_MIDIFILE_JUCEHEADER__ + #include "audio/midi/juce_MidiFile.h" +#endif +#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__ + #include "audio/midi/juce_MidiKeyboardState.h" +#endif +#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ + #include "audio/midi/juce_MidiMessage.h" +#endif +#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__ + #include "audio/midi/juce_MidiMessageCollector.h" +#endif +#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__ + #include "audio/midi/juce_MidiMessageSequence.h" #endif #ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__ #include "audio/plugins/formats/juce_AudioUnitPluginFormat.h" @@ -182,47 +197,32 @@ #ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__ #include "audio/plugins/juce_PluginListComponent.h" #endif -#ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AiffAudioFormat.h" -#endif -#ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioFormat.h" -#endif -#ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioFormatManager.h" -#endif -#ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioFormatReader.h" -#endif -#ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioFormatWriter.h" -#endif -#ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioSubsectionReader.h" +#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__ + #include "audio/processors/juce_AudioPlayHead.h" #endif -#ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioThumbnail.h" +#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__ + #include "audio/processors/juce_AudioProcessor.h" #endif -#ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioThumbnailCache.h" +#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__ + #include "audio/processors/juce_AudioProcessorEditor.h" #endif -#ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_FlacAudioFormat.h" +#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__ + #include "audio/processors/juce_AudioProcessorGraph.h" #endif -#ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_WavAudioFormat.h" +#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__ + #include "audio/processors/juce_AudioProcessorListener.h" #endif -#ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioCDReader.h" +#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__ + #include "audio/processors/juce_AudioProcessorPlayer.h" #endif -#ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_OggVorbisAudioFormat.h" +#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__ + #include "audio/processors/juce_GenericAudioProcessorEditor.h" #endif -#ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ - #include "audio/audio_file_formats/juce_QuickTimeAudioFormat.h" +#ifndef __JUCE_SAMPLER_JUCEHEADER__ + #include "audio/synthesisers/juce_Sampler.h" #endif -#ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ - #include "audio/audio_file_formats/juce_AudioCDBurner.h" +#ifndef __JUCE_SYNTHESISER_JUCEHEADER__ + #include "audio/synthesisers/juce_Synthesiser.h" #endif #ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ #include "events/juce_ActionBroadcaster.h" @@ -269,113 +269,128 @@ #ifndef __JUCE_TIMER_JUCEHEADER__ #include "events/juce_Timer.h" #endif -#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ - #include "gui/graphics/colour/juce_PixelFormats.h" +#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_ArrowButton.h" #endif -#ifndef __JUCE_COLOUR_JUCEHEADER__ - #include "gui/graphics/colour/juce_Colour.h" +#ifndef __JUCE_BUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_Button.h" #endif -#ifndef __JUCE_COLOURS_JUCEHEADER__ - #include "gui/graphics/colour/juce_Colours.h" +#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_DrawableButton.h" #endif -#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ - #include "gui/graphics/colour/juce_ColourGradient.h" +#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_HyperlinkButton.h" #endif -#ifndef __JUCE_TYPEFACE_JUCEHEADER__ - #include "gui/graphics/fonts/juce_Typeface.h" +#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_ImageButton.h" #endif -#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ - #include "gui/graphics/fonts/juce_TextLayout.h" +#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_ShapeButton.h" #endif -#ifndef __JUCE_FONT_JUCEHEADER__ - #include "gui/graphics/fonts/juce_Font.h" +#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_TextButton.h" #endif -#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ - #include "gui/graphics/fonts/juce_GlyphArrangement.h" +#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_ToggleButton.h" #endif -#ifndef __JUCE_FILLTYPE_JUCEHEADER__ - #include "gui/graphics/contexts/juce_FillType.h" +#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ + #include "gui/components/buttons/juce_ToolbarButton.h" #endif -#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ - #include "gui/graphics/contexts/juce_Justification.h" +#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ + #include "gui/components/code_editor/juce_CodeDocument.h" #endif -#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ - #include "gui/graphics/contexts/juce_RectanglePlacement.h" +#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ + #include "gui/components/code_editor/juce_CodeEditorComponent.h" #endif -#ifndef __JUCE_EDGETABLE_JUCEHEADER__ - #include "gui/graphics/contexts/juce_EdgeTable.h" +#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ + #include "gui/components/code_editor/juce_CodeTokeniser.h" #endif -#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ - #include "gui/graphics/contexts/juce_LowLevelGraphicsContext.h" +#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ + #include "gui/components/code_editor/juce_CPlusPlusCodeTokeniser.h" #endif -#ifndef __JUCE_GRAPHICS_JUCEHEADER__ - #include "gui/graphics/contexts/juce_Graphics.h" +#ifndef __JUCE_COMBOBOX_JUCEHEADER__ + #include "gui/components/controls/juce_ComboBox.h" #endif -#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ - #include "gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h" +#ifndef __JUCE_LABEL_JUCEHEADER__ + #include "gui/components/controls/juce_Label.h" #endif -#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ - #include "gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h" +#ifndef __JUCE_LISTBOX_JUCEHEADER__ + #include "gui/components/controls/juce_ListBox.h" #endif -#ifndef __JUCE_PATH_JUCEHEADER__ - #include "gui/graphics/geometry/juce_Path.h" +#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ + #include "gui/components/controls/juce_ProgressBar.h" #endif -#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ - #include "gui/graphics/geometry/juce_BorderSize.h" +#ifndef __JUCE_SLIDER_JUCEHEADER__ + #include "gui/components/controls/juce_Slider.h" #endif -#ifndef __JUCE_LINE_JUCEHEADER__ - #include "gui/graphics/geometry/juce_Line.h" +#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ + #include "gui/components/controls/juce_SliderListener.h" #endif -#ifndef __JUCE_POINT_JUCEHEADER__ - #include "gui/graphics/geometry/juce_Point.h" +#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ + #include "gui/components/controls/juce_TableHeaderComponent.h" #endif -#ifndef __JUCE_RECTANGLE_JUCEHEADER__ - #include "gui/graphics/geometry/juce_Rectangle.h" +#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ + #include "gui/components/controls/juce_TableListBox.h" #endif -#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ - #include "gui/graphics/geometry/juce_PathStrokeType.h" +#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ + #include "gui/components/controls/juce_TextEditor.h" #endif -#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ - #include "gui/graphics/geometry/juce_PositionedRectangle.h" +#ifndef __JUCE_TOOLBAR_JUCEHEADER__ + #include "gui/components/controls/juce_Toolbar.h" #endif -#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ - #include "gui/graphics/geometry/juce_RectangleList.h" +#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ + #include "gui/components/controls/juce_ToolbarItemComponent.h" #endif -#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ - #include "gui/graphics/geometry/juce_PathIterator.h" +#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ + #include "gui/components/controls/juce_ToolbarItemFactory.h" #endif -#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ - #include "gui/graphics/geometry/juce_AffineTransform.h" +#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ + #include "gui/components/controls/juce_ToolbarItemPalette.h" #endif -#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ - #include "gui/graphics/imaging/juce_CameraDevice.h" +#ifndef __JUCE_TREEVIEW_JUCEHEADER__ + #include "gui/components/controls/juce_TreeView.h" #endif -#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ - #include "gui/graphics/imaging/juce_ImageCache.h" +#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.h" #endif -#ifndef __JUCE_IMAGE_JUCEHEADER__ - #include "gui/graphics/imaging/juce_Image.h" +#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ + #include "gui/components/filebrowser/juce_DirectoryContentsList.h" #endif -#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ - #include "gui/graphics/imaging/juce_ImageFileFormat.h" +#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileBrowserComponent.h" #endif -#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ - #include "gui/graphics/imaging/juce_ImageConvolutionKernel.h" +#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileBrowserListener.h" #endif -#ifndef __JUCE_DRAWABLE_JUCEHEADER__ - #include "gui/graphics/drawables/juce_Drawable.h" +#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileChooser.h" #endif -#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ - #include "gui/graphics/drawables/juce_DrawableComposite.h" +#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileChooserDialogBox.h" #endif -#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ - #include "gui/graphics/drawables/juce_DrawableImage.h" +#ifndef __JUCE_FILEFILTER_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileFilter.h" #endif -#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ - #include "gui/graphics/drawables/juce_DrawableText.h" +#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileListComponent.h" #endif -#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ - #include "gui/graphics/drawables/juce_DrawablePath.h" +#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FilenameComponent.h" +#endif +#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FilePreviewComponent.h" +#endif +#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileSearchPathListComponent.h" +#endif +#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_FileTreeComponent.h" +#endif +#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ + #include "gui/components/filebrowser/juce_ImagePreviewComponent.h" +#endif +#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ + #include "gui/components/filebrowser/juce_WildcardFileFilter.h" #endif #ifndef __JUCE_COMPONENT_JUCEHEADER__ #include "gui/components/juce_Component.h" @@ -389,74 +404,71 @@ #ifndef __JUCE_DESKTOP_JUCEHEADER__ #include "gui/components/juce_Desktop.h" #endif -#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_ArrowButton.h" -#endif -#ifndef __JUCE_BUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_Button.h" +#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ + #include "gui/components/keyboard/juce_KeyboardFocusTraverser.h" #endif -#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_DrawableButton.h" +#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ + #include "gui/components/keyboard/juce_KeyListener.h" #endif -#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_HyperlinkButton.h" +#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ + #include "gui/components/keyboard/juce_KeyMappingEditorComponent.h" #endif -#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_ImageButton.h" +#ifndef __JUCE_KEYPRESS_JUCEHEADER__ + #include "gui/components/keyboard/juce_KeyPress.h" #endif -#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_ShapeButton.h" +#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ + #include "gui/components/keyboard/juce_KeyPressMappingSet.h" #endif -#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_TextButton.h" +#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ + #include "gui/components/keyboard/juce_ModifierKeys.h" #endif -#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_ToggleButton.h" +#ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ + #include "gui/components/layout/juce_ComponentAnimator.h" #endif -#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__ - #include "gui/components/buttons/juce_ToolbarButton.h" +#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ + #include "gui/components/layout/juce_ComponentBoundsConstrainer.h" #endif -#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ - #include "gui/graphics/effects/juce_DropShadowEffect.h" +#ifndef __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__ + #include "gui/components/layout/juce_ComponentMovementWatcher.h" #endif -#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ - #include "gui/graphics/effects/juce_GlowEffect.h" +#ifndef __JUCE_GROUPCOMPONENT_JUCEHEADER__ + #include "gui/components/layout/juce_GroupComponent.h" #endif -#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ - #include "gui/graphics/effects/juce_ImageEffectFilter.h" +#ifndef __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__ + #include "gui/components/layout/juce_MultiDocumentPanel.h" #endif -#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ - #include "gui/graphics/effects/juce_ReduceOpacityEffect.h" +#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ + #include "gui/components/layout/juce_ResizableBorderComponent.h" #endif -#ifndef __JUCE_KEYLISTENER_JUCEHEADER__ - #include "gui/components/keyboard/juce_KeyListener.h" +#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ + #include "gui/components/layout/juce_ResizableCornerComponent.h" #endif -#ifndef __JUCE_KEYPRESS_JUCEHEADER__ - #include "gui/components/keyboard/juce_KeyPress.h" +#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ + #include "gui/components/layout/juce_ScrollBar.h" #endif -#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__ - #include "gui/components/keyboard/juce_KeyPressMappingSet.h" +#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ + #include "gui/components/layout/juce_StretchableLayoutManager.h" #endif -#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ - #include "gui/components/keyboard/juce_KeyboardFocusTraverser.h" +#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ + #include "gui/components/layout/juce_StretchableLayoutResizerBar.h" #endif -#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ - #include "gui/components/keyboard/juce_ModifierKeys.h" +#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ + #include "gui/components/layout/juce_StretchableObjectResizer.h" #endif -#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__ - #include "gui/components/keyboard/juce_KeyMappingEditorComponent.h" +#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__ + #include "gui/components/layout/juce_TabbedButtonBar.h" #endif -#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ - #include "gui/components/code_editor/juce_CodeEditorComponent.h" +#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__ + #include "gui/components/layout/juce_TabbedComponent.h" #endif -#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ - #include "gui/components/code_editor/juce_CPlusPlusCodeTokeniser.h" +#ifndef __JUCE_VIEWPORT_JUCEHEADER__ + #include "gui/components/layout/juce_Viewport.h" #endif -#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ - #include "gui/components/code_editor/juce_CodeDocument.h" +#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ + #include "gui/components/lookandfeel/juce_LookAndFeel.h" #endif -#ifndef __JUCE_CODETOKENISER_JUCEHEADER__ - #include "gui/components/code_editor/juce_CodeTokeniser.h" +#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ + #include "gui/components/lookandfeel/juce_OldSchoolLookAndFeel.h" #endif #ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__ #include "gui/components/menus/juce_MenuBarComponent.h" @@ -473,6 +485,9 @@ #ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__ #include "gui/components/mouse/juce_ComponentDragger.h" #endif +#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ + #include "gui/components/mouse/juce_DragAndDropContainer.h" +#endif #ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__ #include "gui/components/mouse/juce_DragAndDropTarget.h" #endif @@ -497,51 +512,6 @@ #ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ #include "gui/components/mouse/juce_TooltipClient.h" #endif -#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__ - #include "gui/components/mouse/juce_DragAndDropContainer.h" -#endif -#ifndef __JUCE_COMBOBOX_JUCEHEADER__ - #include "gui/components/controls/juce_ComboBox.h" -#endif -#ifndef __JUCE_LABEL_JUCEHEADER__ - #include "gui/components/controls/juce_Label.h" -#endif -#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__ - #include "gui/components/controls/juce_ProgressBar.h" -#endif -#ifndef __JUCE_SLIDER_JUCEHEADER__ - #include "gui/components/controls/juce_Slider.h" -#endif -#ifndef __JUCE_SLIDERLISTENER_JUCEHEADER__ - #include "gui/components/controls/juce_SliderListener.h" -#endif -#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__ - #include "gui/components/controls/juce_TableHeaderComponent.h" -#endif -#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__ - #include "gui/components/controls/juce_TableListBox.h" -#endif -#ifndef __JUCE_TOOLBAR_JUCEHEADER__ - #include "gui/components/controls/juce_Toolbar.h" -#endif -#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__ - #include "gui/components/controls/juce_ToolbarItemFactory.h" -#endif -#ifndef __JUCE_LISTBOX_JUCEHEADER__ - #include "gui/components/controls/juce_ListBox.h" -#endif -#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ - #include "gui/components/controls/juce_ToolbarItemPalette.h" -#endif -#ifndef __JUCE_TREEVIEW_JUCEHEADER__ - #include "gui/components/controls/juce_TreeView.h" -#endif -#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ - #include "gui/components/controls/juce_TextEditor.h" -#endif -#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ - #include "gui/components/controls/juce_ToolbarItemComponent.h" -#endif #ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ #include "gui/components/properties/juce_BooleanPropertyComponent.h" #endif @@ -551,105 +521,66 @@ #ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ #include "gui/components/properties/juce_ChoicePropertyComponent.h" #endif -#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ - #include "gui/components/properties/juce_PropertyPanel.h" -#endif #ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ #include "gui/components/properties/juce_PropertyComponent.h" #endif +#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ + #include "gui/components/properties/juce_PropertyPanel.h" +#endif #ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ #include "gui/components/properties/juce_SliderPropertyComponent.h" #endif #ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__ #include "gui/components/properties/juce_TextPropertyComponent.h" #endif -#ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ - #include "gui/components/layout/juce_ComponentAnimator.h" -#endif -#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__ - #include "gui/components/layout/juce_ComponentBoundsConstrainer.h" -#endif -#ifndef __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__ - #include "gui/components/layout/juce_ComponentMovementWatcher.h" -#endif -#ifndef __JUCE_GROUPCOMPONENT_JUCEHEADER__ - #include "gui/components/layout/juce_GroupComponent.h" -#endif -#ifndef __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__ - #include "gui/components/layout/juce_MultiDocumentPanel.h" -#endif -#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__ - #include "gui/components/layout/juce_ResizableBorderComponent.h" -#endif -#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__ - #include "gui/components/layout/juce_ResizableCornerComponent.h" -#endif -#ifndef __JUCE_SCROLLBAR_JUCEHEADER__ - #include "gui/components/layout/juce_ScrollBar.h" -#endif -#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__ - #include "gui/components/layout/juce_StretchableLayoutManager.h" -#endif -#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__ - #include "gui/components/layout/juce_StretchableLayoutResizerBar.h" -#endif -#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__ - #include "gui/components/layout/juce_StretchableObjectResizer.h" -#endif -#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__ - #include "gui/components/layout/juce_TabbedButtonBar.h" -#endif -#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__ - #include "gui/components/layout/juce_TabbedComponent.h" -#endif -#ifndef __JUCE_VIEWPORT_JUCEHEADER__ - #include "gui/components/layout/juce_Viewport.h" -#endif -#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.h" +#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_ActiveXControlComponent.h" #endif -#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__ - #include "gui/components/filebrowser/juce_DirectoryContentsList.h" +#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_AudioDeviceSelectorComponent.h" #endif -#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileBrowserListener.h" +#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_BubbleComponent.h" #endif -#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileListComponent.h" +#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_BubbleMessageComponent.h" #endif -#ifndef __JUCE_FILEFILTER_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileFilter.h" +#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ + #include "gui/components/special/juce_ColourSelector.h" #endif -#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileTreeComponent.h" +#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ + #include "gui/components/special/juce_DropShadower.h" #endif -#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileChooserDialogBox.h" +#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_MagnifierComponent.h" #endif -#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FilePreviewComponent.h" +#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_MidiKeyboardComponent.h" #endif -#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FilenameComponent.h" +#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_NSViewComponent.h" #endif -#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileSearchPathListComponent.h" +#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_OpenGLComponent.h" #endif -#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ - #include "gui/components/filebrowser/juce_WildcardFileFilter.h" +#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ + #include "gui/components/special/juce_PreferencesPanel.h" #endif -#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_ImagePreviewComponent.h" +#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_QuickTimeMovieComponent.h" #endif -#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileBrowserComponent.h" +#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_SystemTrayIconComponent.h" #endif -#ifndef __JUCE_FILECHOOSER_JUCEHEADER__ - #include "gui/components/filebrowser/juce_FileChooser.h" +#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ + #include "gui/components/special/juce_WebBrowserComponent.h" #endif #ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ #include "gui/components/windows/juce_AlertWindow.h" #endif +#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ + #include "gui/components/windows/juce_ComponentPeer.h" +#endif #ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__ #include "gui/components/windows/juce_DialogWindow.h" #endif @@ -662,65 +593,134 @@ #ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__ #include "gui/components/windows/juce_SplashScreen.h" #endif +#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ + #include "gui/components/windows/juce_ThreadWithProgressWindow.h" +#endif #ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ #include "gui/components/windows/juce_TooltipWindow.h" #endif #ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__ #include "gui/components/windows/juce_TopLevelWindow.h" #endif -#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__ - #include "gui/components/windows/juce_ThreadWithProgressWindow.h" +#ifndef __JUCE_COLOUR_JUCEHEADER__ + #include "gui/graphics/colour/juce_Colour.h" #endif -#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__ - #include "gui/components/windows/juce_ComponentPeer.h" +#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ + #include "gui/graphics/colour/juce_ColourGradient.h" #endif -#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_ActiveXControlComponent.h" +#ifndef __JUCE_COLOURS_JUCEHEADER__ + #include "gui/graphics/colour/juce_Colours.h" #endif -#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_AudioDeviceSelectorComponent.h" +#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ + #include "gui/graphics/colour/juce_PixelFormats.h" #endif -#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_BubbleComponent.h" +#ifndef __JUCE_EDGETABLE_JUCEHEADER__ + #include "gui/graphics/contexts/juce_EdgeTable.h" #endif -#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_BubbleMessageComponent.h" +#ifndef __JUCE_FILLTYPE_JUCEHEADER__ + #include "gui/graphics/contexts/juce_FillType.h" #endif -#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__ - #include "gui/components/special/juce_ColourSelector.h" +#ifndef __JUCE_GRAPHICS_JUCEHEADER__ + #include "gui/graphics/contexts/juce_Graphics.h" #endif -#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__ - #include "gui/components/special/juce_DropShadower.h" +#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ + #include "gui/graphics/contexts/juce_Justification.h" #endif -#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_MagnifierComponent.h" +#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ + #include "gui/graphics/contexts/juce_LowLevelGraphicsContext.h" #endif -#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_MidiKeyboardComponent.h" +#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ + #include "gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h" #endif -#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_NSViewComponent.h" +#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ + #include "gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h" #endif -#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_OpenGLComponent.h" +#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ + #include "gui/graphics/contexts/juce_RectanglePlacement.h" #endif -#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ - #include "gui/components/special/juce_PreferencesPanel.h" +#ifndef __JUCE_DRAWABLE_JUCEHEADER__ + #include "gui/graphics/drawables/juce_Drawable.h" #endif -#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_WebBrowserComponent.h" +#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__ + #include "gui/graphics/drawables/juce_DrawableComposite.h" #endif -#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_SystemTrayIconComponent.h" +#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ + #include "gui/graphics/drawables/juce_DrawableImage.h" #endif -#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ - #include "gui/components/special/juce_QuickTimeMovieComponent.h" +#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ + #include "gui/graphics/drawables/juce_DrawablePath.h" #endif -#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__ - #include "gui/components/lookandfeel/juce_LookAndFeel.h" +#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ + #include "gui/graphics/drawables/juce_DrawableText.h" #endif -#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__ - #include "gui/components/lookandfeel/juce_OldSchoolLookAndFeel.h" +#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__ + #include "gui/graphics/effects/juce_DropShadowEffect.h" +#endif +#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__ + #include "gui/graphics/effects/juce_GlowEffect.h" +#endif +#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ + #include "gui/graphics/effects/juce_ImageEffectFilter.h" +#endif +#ifndef __JUCE_REDUCEOPACITYEFFECT_JUCEHEADER__ + #include "gui/graphics/effects/juce_ReduceOpacityEffect.h" +#endif +#ifndef __JUCE_FONT_JUCEHEADER__ + #include "gui/graphics/fonts/juce_Font.h" +#endif +#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ + #include "gui/graphics/fonts/juce_GlyphArrangement.h" +#endif +#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ + #include "gui/graphics/fonts/juce_TextLayout.h" +#endif +#ifndef __JUCE_TYPEFACE_JUCEHEADER__ + #include "gui/graphics/fonts/juce_Typeface.h" +#endif +#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ + #include "gui/graphics/geometry/juce_AffineTransform.h" +#endif +#ifndef __JUCE_BORDERSIZE_JUCEHEADER__ + #include "gui/graphics/geometry/juce_BorderSize.h" +#endif +#ifndef __JUCE_LINE_JUCEHEADER__ + #include "gui/graphics/geometry/juce_Line.h" +#endif +#ifndef __JUCE_PATH_JUCEHEADER__ + #include "gui/graphics/geometry/juce_Path.h" +#endif +#ifndef __JUCE_PATHITERATOR_JUCEHEADER__ + #include "gui/graphics/geometry/juce_PathIterator.h" +#endif +#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ + #include "gui/graphics/geometry/juce_PathStrokeType.h" +#endif +#ifndef __JUCE_POINT_JUCEHEADER__ + #include "gui/graphics/geometry/juce_Point.h" +#endif +#ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ + #include "gui/graphics/geometry/juce_PositionedRectangle.h" +#endif +#ifndef __JUCE_RECTANGLE_JUCEHEADER__ + #include "gui/graphics/geometry/juce_Rectangle.h" +#endif +#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ + #include "gui/graphics/geometry/juce_RectangleList.h" +#endif +#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ + #include "gui/graphics/imaging/juce_CameraDevice.h" +#endif +#ifndef __JUCE_IMAGE_JUCEHEADER__ + #include "gui/graphics/imaging/juce_Image.h" +#endif +#ifndef __JUCE_IMAGECACHE_JUCEHEADER__ + #include "gui/graphics/imaging/juce_ImageCache.h" +#endif +#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__ + #include "gui/graphics/imaging/juce_ImageConvolutionKernel.h" +#endif +#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ + #include "gui/graphics/imaging/juce_ImageFileFormat.h" #endif #ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ #include "utilities/juce_DeletedAtShutdown.h" diff --git a/src/juce_core_includes.h b/src/juce_core_includes.h index e429ea620a..503fdf062c 100644 --- a/src/juce_core_includes.h +++ b/src/juce_core_includes.h @@ -26,6 +26,51 @@ #ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ #define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ +#ifndef __JUCE_ARRAY_JUCEHEADER__ + #include "containers/juce_Array.h" +#endif +#ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ + #include "containers/juce_ArrayAllocationBase.h" +#endif +#ifndef __JUCE_BITARRAY_JUCEHEADER__ + #include "containers/juce_BitArray.h" +#endif +#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ + #include "containers/juce_ElementComparator.h" +#endif +#ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ + #include "containers/juce_HeapBlock.h" +#endif +#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ + #include "containers/juce_MemoryBlock.h" +#endif +#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ + #include "containers/juce_OwnedArray.h" +#endif +#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ + #include "containers/juce_PropertySet.h" +#endif +#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ + #include "containers/juce_ReferenceCountedArray.h" +#endif +#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ + #include "containers/juce_ReferenceCountedObject.h" +#endif +#ifndef __JUCE_SORTEDSET_JUCEHEADER__ + #include "containers/juce_SortedSet.h" +#endif +#ifndef __JUCE_SPARSESET_JUCEHEADER__ + #include "containers/juce_SparseSet.h" +#endif +#ifndef __JUCE_VALUETREE_JUCEHEADER__ + #include "containers/juce_ValueTree.h" +#endif +#ifndef __JUCE_VARIANT_JUCEHEADER__ + #include "containers/juce_Variant.h" +#endif +#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ + #include "containers/juce_VoidArray.h" +#endif #ifndef __JUCE_ATOMIC_JUCEHEADER__ #include "core/juce_Atomic.h" #endif @@ -41,8 +86,8 @@ #ifndef __JUCE_LOGGER_JUCEHEADER__ #include "core/juce_Logger.h" #endif -#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ - #include "core/juce_PlatformUtilities.h" +#ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ + #include "core/juce_MathsFunctions.h" #endif #ifndef __JUCE_MEMORY_JUCEHEADER__ #include "core/juce_Memory.h" @@ -53,8 +98,8 @@ #ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ #include "core/juce_PlatformDefs.h" #endif -#ifndef __JUCE_SINGLETON_JUCEHEADER__ - #include "core/juce_Singleton.h" +#ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ + #include "core/juce_PlatformUtilities.h" #endif #ifndef __JUCE_RANDOM_JUCEHEADER__ #include "core/juce_Random.h" @@ -62,65 +107,35 @@ #ifndef __JUCE_RELATIVETIME_JUCEHEADER__ #include "core/juce_RelativeTime.h" #endif -#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ - #include "core/juce_SystemStats.h" -#endif -#ifndef __JUCE_TIME_JUCEHEADER__ - #include "core/juce_Time.h" -#endif -#ifndef __JUCE_UUID_JUCEHEADER__ - #include "core/juce_Uuid.h" +#ifndef __JUCE_SINGLETON_JUCEHEADER__ + #include "core/juce_Singleton.h" #endif #ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ #include "core/juce_StandardHeader.h" #endif -#ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ - #include "core/juce_MathsFunctions.h" +#ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ + #include "core/juce_SystemStats.h" #endif #ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ #include "core/juce_TargetPlatform.h" #endif -#ifndef __JUCE_ARRAY_JUCEHEADER__ - #include "containers/juce_Array.h" -#endif -#ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ - #include "containers/juce_ArrayAllocationBase.h" -#endif -#ifndef __JUCE_VARIANT_JUCEHEADER__ - #include "containers/juce_Variant.h" -#endif -#ifndef __JUCE_BITARRAY_JUCEHEADER__ - #include "containers/juce_BitArray.h" -#endif -#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ - #include "containers/juce_ElementComparator.h" -#endif -#ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ - #include "containers/juce_MemoryBlock.h" -#endif -#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ - #include "containers/juce_OwnedArray.h" -#endif -#ifndef __JUCE_PROPERTYSET_JUCEHEADER__ - #include "containers/juce_PropertySet.h" -#endif -#ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ - #include "containers/juce_ReferenceCountedArray.h" +#ifndef __JUCE_TIME_JUCEHEADER__ + #include "core/juce_Time.h" #endif -#ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ - #include "containers/juce_ReferenceCountedObject.h" +#ifndef __JUCE_UUID_JUCEHEADER__ + #include "core/juce_Uuid.h" #endif -#ifndef __JUCE_SORTEDSET_JUCEHEADER__ - #include "containers/juce_SortedSet.h" +#ifndef __JUCE_BLOWFISH_JUCEHEADER__ + #include "cryptography/juce_BlowFish.h" #endif -#ifndef __JUCE_SPARSESET_JUCEHEADER__ - #include "containers/juce_SparseSet.h" +#ifndef __JUCE_MD5_JUCEHEADER__ + #include "cryptography/juce_MD5.h" #endif -#ifndef __JUCE_VOIDARRAY_JUCEHEADER__ - #include "containers/juce_VoidArray.h" +#ifndef __JUCE_PRIMES_JUCEHEADER__ + #include "cryptography/juce_Primes.h" #endif -#ifndef __JUCE_VALUETREE_JUCEHEADER__ - #include "containers/juce_ValueTree.h" +#ifndef __JUCE_RSAKEY_JUCEHEADER__ + #include "cryptography/juce_RSAKey.h" #endif #ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ #include "io/files/juce_DirectoryIterator.h" @@ -143,18 +158,6 @@ #ifndef __JUCE_ZIPFILE_JUCEHEADER__ #include "io/files/juce_ZipFile.h" #endif -#ifndef __JUCE_BLOWFISH_JUCEHEADER__ - #include "cryptography/juce_BlowFish.h" -#endif -#ifndef __JUCE_MD5_JUCEHEADER__ - #include "cryptography/juce_MD5.h" -#endif -#ifndef __JUCE_PRIMES_JUCEHEADER__ - #include "cryptography/juce_Primes.h" -#endif -#ifndef __JUCE_RSAKEY_JUCEHEADER__ - #include "cryptography/juce_RSAKey.h" -#endif #ifndef __JUCE_SOCKET_JUCEHEADER__ #include "io/network/juce_Socket.h" #endif @@ -191,15 +194,15 @@ #ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ #include "io/streams/juce_SubregionStream.h" #endif +#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ + #include "text/juce_CharacterFunctions.h" +#endif #ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ #include "text/juce_LocalisedStrings.h" #endif #ifndef __JUCE_STRING_JUCEHEADER__ #include "text/juce_String.h" #endif -#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ - #include "text/juce_CharacterFunctions.h" -#endif #ifndef __JUCE_STRINGARRAY_JUCEHEADER__ #include "text/juce_StringArray.h" #endif diff --git a/src/native/linux/juce_linux_JackAudio.cpp b/src/native/linux/juce_linux_JackAudio.cpp index 5d508325ba..7b70c959db 100644 --- a/src/native/linux/juce_linux_JackAudio.cpp +++ b/src/native/linux/juce_linux_JackAudio.cpp @@ -127,8 +127,6 @@ public: outputId (outputId_), isOpen_ (false), callback (0), - inChans (0), - outChans (0), totalNumberOfInputChannels (0), totalNumberOfOutputChannels (0) { @@ -167,8 +165,8 @@ public: JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)); } - inChans = (float**) juce_calloc (sizeof (float*) * (totalNumberOfInputChannels + 2)); - outChans = (float**) juce_calloc (sizeof (float*) * (totalNumberOfOutputChannels + 2)); + inChans.calloc (totalNumberOfInputChannels + 2); + outChans.calloc (totalNumberOfOutputChannels + 2); } } @@ -180,9 +178,6 @@ public: JUCE_NAMESPACE::jack_client_close (client); client = 0; } - - juce_free (inChans); - juce_free (outChans); } const StringArray getChannelNames (bool forInput) const @@ -447,8 +442,7 @@ private: AudioIODeviceCallback* callback; CriticalSection callbackLock; - float** inChans; - float** outChans; + HeapBlock inChans, outChans; int totalNumberOfInputChannels; int totalNumberOfOutputChannels; VoidArray inputPorts, outputPorts; diff --git a/src/native/linux/juce_linux_Midi.cpp b/src/native/linux/juce_linux_Midi.cpp index be1f1acb9c..7ca71324e5 100644 --- a/src/native/linux/juce_linux_Midi.cpp +++ b/src/native/linux/juce_linux_Midi.cpp @@ -301,7 +301,7 @@ public: if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) { - uint8* const buffer = (uint8*) juce_malloc (maxEventSize); + HeapBlock buffer (maxEventSize); const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); @@ -345,7 +345,6 @@ public: } snd_midi_event_free (midiParser); - juce_free (buffer); } }; diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 323b941250..d7bdebb92b 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -392,7 +392,7 @@ static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& i { const int width = image.getWidth(); const int height = image.getHeight(); - uint32* const colour = (uint32*) juce_malloc (width * height * sizeof (uint32)); + HeapBlock colour (width * height); int index = 0; for (int y = 0; y < height; ++y) @@ -408,7 +408,6 @@ static Pixmap juce_createColourPixmapFromImage (Display* display, const Image& i GC gc = XCreateGC (display, pixmap, 0, 0); XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height); XFreeGC (display, gc); - juce_free (colour); return pixmap; } @@ -418,7 +417,8 @@ static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& ima const int width = image.getWidth(); const int height = image.getHeight(); const int stride = (width + 7) >> 3; - uint8* const mask = (uint8*) juce_calloc (stride * height); + HeapBlock mask; + mask.calloc (stride * height); const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); for (int y = 0; y < height; ++y) @@ -433,12 +433,8 @@ static Pixmap juce_createMaskPixmapFromImage (Display* display, const Image& ima } } - Pixmap pixmap = XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), - (char*) mask, width, height, 1, 0, 1); - - juce_free (mask); - - return pixmap; + return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display), + (char*) mask, width, height, 1, 0, 1); } @@ -506,7 +502,8 @@ public: if (! usingXShm) #endif { - imageData = (uint8*) juce_malloc (lineStride * h); + imageDataAllocated.malloc (lineStride * h); + imageData = imageDataAllocated; if (format_ == ARGB && clearImage) zeromem (imageData, h * lineStride); @@ -534,7 +531,8 @@ public: const int pixelStride = 2; const int lineStride = ((w * pixelStride + 3) & ~3); - xImage->data = (char*) juce_malloc (lineStride * h); + imageData16Bit.malloc (lineStride * h); + xImage->data = imageData16Bit; xImage->bitmap_pad = 16; xImage->depth = pixelStride * 8; xImage->bytes_per_line = lineStride; @@ -567,13 +565,9 @@ public: else #endif { - juce_free (xImage->data); xImage->data = 0; XDestroyImage (xImage); } - - if (! is16Bit) - imageData = 0; // to stop the base class freeing this (for the 16-bit version we want it to free it) } void blitToWindow (Window window, int dx, int dy, int dw, int dh, int sx, int sy) @@ -629,6 +623,7 @@ public: private: XImage* xImage; const bool is16Bit; + HeapBlock imageData16Bit; #if JUCE_USE_XSHM XShmSegmentInfo segmentInfo; @@ -1094,7 +1089,7 @@ public: void setIcon (const Image& newIcon) { const int dataSize = newIcon.getWidth() * newIcon.getHeight() + 2; - unsigned long* const data = (unsigned long*) juce_malloc (dataSize * sizeof (uint32)); + HeapBlock data (dataSize); int index = 0; data[index++] = newIcon.getWidth(); @@ -1109,8 +1104,6 @@ public: XA_CARDINAL, 32, PropModeReplace, (unsigned char*) data, dataSize); - juce_free (data); - deleteIconPixmaps(); XWMHints* wmHints = XGetWMHints (display, windowH); @@ -2739,8 +2732,9 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot } const int stride = (cursorW + 7) >> 3; - uint8* const maskPlane = (uint8*) juce_calloc (stride * cursorH); - uint8* const sourcePlane = (uint8*) juce_calloc (stride * cursorH); + HeapBlock maskPlane, sourcePlane; + maskPlane.calloc (stride * cursorH); + sourcePlane.calloc (stride * cursorH); const bool msbfirst = (BitmapBitOrder (display) == MSBFirst); @@ -2764,9 +2758,6 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot Pixmap sourcePixmap = XCreatePixmapFromBitmapData (display, root, (char*) sourcePlane, cursorW, cursorH, 0xffff, 0, 1); Pixmap maskPixmap = XCreatePixmapFromBitmapData (display, root, (char*) maskPlane, cursorW, cursorH, 0xffff, 0, 1); - juce_free (maskPlane); - juce_free (sourcePlane); - XColor white, black; black.red = black.green = black.blue = 0; white.red = white.green = white.blue = 0xffff; diff --git a/src/native/mac/juce_mac_CoreAudio.cpp b/src/native/mac/juce_mac_CoreAudio.cpp index 8c05590627..37eadd462d 100644 --- a/src/native/mac/juce_mac_CoreAudio.cpp +++ b/src/native/mac/juce_mac_CoreAudio.cpp @@ -77,16 +77,11 @@ public: started (false), sampleRate (0), bufferSize (512), - audioBuffer (0), numInputChans (0), numOutputChans (0), callbacksAllowed (true), numInputChannelInfos (0), - numOutputChannelInfos (0), - tempInputBuffers (0), - tempOutputBuffers (0), - inputChannelInfo (0), - outputChannelInfo (0) + numOutputChannelInfos (0) { jassert (deviceID != 0); @@ -111,24 +106,15 @@ public: stop (false); delete inputDevice; - - juce_free (audioBuffer); - juce_free (tempInputBuffers); - juce_free (tempOutputBuffers); - juce_free (inputChannelInfo); - juce_free (outputChannelInfo); } void allocateTempBuffers() { const int tempBufSize = bufferSize + 4; - juce_free (audioBuffer); - audioBuffer = (float*) juce_calloc ((numInputChans + numOutputChans) * tempBufSize * sizeof (float)); + audioBuffer.calloc ((numInputChans + numOutputChans) * tempBufSize); - juce_free (tempInputBuffers); - tempInputBuffers = (float**) juce_calloc (sizeof (float*) * (numInputChans + 2)); - juce_free (tempOutputBuffers); - tempOutputBuffers = (float**) juce_calloc (sizeof (float*) * (numOutputChans + 2)); + tempInputBuffers.calloc (numInputChans + 2); + tempOutputBuffers.calloc (numOutputChans + 2); int i, count = 0; for (i = 0; i < numInputChans; ++i) @@ -151,7 +137,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioBufferList* const bufList = (AudioBufferList*) juce_calloc (size); + HeapBlock bufList; + bufList.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) { @@ -211,8 +198,6 @@ public: } } } - - juce_free (bufList); } } @@ -252,7 +237,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioValueRange* ranges = (AudioValueRange*) juce_calloc (size); + HeapBlock ranges; + ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) { @@ -273,8 +259,6 @@ public: if (bufferSize > 0) bufferSizes.addIfNotAlreadyThere (bufferSize); } - - juce_free (ranges); } if (bufferSizes.size() == 0 && bufferSize > 0) @@ -288,7 +272,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioValueRange* ranges = (AudioValueRange*) juce_calloc (size); + HeapBlock ranges; + ranges.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) { @@ -307,8 +292,6 @@ public: } } } - - juce_free (ranges); } if (sampleRates.size() == 0 && sampleRate > 0) @@ -340,12 +323,10 @@ public: inChanNames.clear(); outChanNames.clear(); - juce_free (inputChannelInfo); - inputChannelInfo = (CallbackDetailsForChannel*) juce_calloc (sizeof (CallbackDetailsForChannel) * (numInputChans + 2)); + inputChannelInfo.calloc (numInputChans + 2); numInputChannelInfos = 0; - juce_free (outputChannelInfo); - outputChannelInfo = (CallbackDetailsForChannel*) juce_calloc (sizeof (CallbackDetailsForChannel) * (numOutputChans + 2)); + outputChannelInfo.calloc (numOutputChans + 2); numOutputChannelInfos = 0; fillInChannelInfo (true); @@ -356,36 +337,31 @@ public: const StringArray getSources (bool input) { StringArray s; - int num = 0; - OSType* types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + for (int i = 0; i < num; ++i) { - for (int i = 0; i < num; ++i) - { - AudioValueTranslation avt; - char buffer[256]; + AudioValueTranslation avt; + char buffer[256]; - avt.mInputData = (void*) &(types[i]); - avt.mInputDataSize = sizeof (UInt32); - avt.mOutputData = buffer; - avt.mOutputDataSize = 256; + avt.mInputData = (void*) &(types[i]); + avt.mInputDataSize = sizeof (UInt32); + avt.mOutputData = buffer; + avt.mOutputDataSize = 256; - UInt32 transSize = sizeof (avt); + UInt32 transSize = sizeof (avt); - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyDataSourceNameForID; - pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; - pa.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress pa; + pa.mSelector = kAudioDevicePropertyDataSourceNameForID; + pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + pa.mElement = kAudioObjectPropertyElementMaster; - if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &transSize, &avt))) - { - DBG (buffer); - s.add (buffer); - } + if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &transSize, &avt))) + { + DBG (buffer); + s.add (buffer); } - - juce_free (types); } return s; @@ -406,21 +382,16 @@ public: { if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ¤tSourceID))) { - int num = 0; - OSType* const types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + for (int i = 0; i < num; ++i) { - for (int i = 0; i < num; ++i) + if (types[num] == currentSourceID) { - if (types[num] == currentSourceID) - { - result = i; - break; - } + result = i; + break; } - - juce_free (types); } } } @@ -432,24 +403,19 @@ public: { if (deviceID != 0) { - int num = 0; - OSType* types = getAllDataSourcesForDevice (deviceID, input, num); + HeapBlock types; + const int num = getAllDataSourcesForDevice (deviceID, input, types); - if (types != 0) + if (((unsigned int) index) < (unsigned int) num) { - if (((unsigned int) index) < (unsigned int) num) - { - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyDataSource; - pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; - pa.mElement = kAudioObjectPropertyElementMaster; - - OSType typeId = types[index]; + AudioObjectPropertyAddress pa; + pa.mSelector = kAudioDevicePropertyDataSource; + pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + pa.mElement = kAudioObjectPropertyElementMaster; - OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (typeId), &typeId)); - } + OSType typeId = types[index]; - juce_free (types); + OK (AudioObjectSetPropertyData (deviceID, &pa, 0, 0, sizeof (typeId), &typeId)); } } } @@ -764,7 +730,8 @@ public: && AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr && size > 0) { - AudioDeviceID* devs = (AudioDeviceID*) juce_calloc (size); + HeapBlock devs; + devs.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, devs))) { @@ -786,8 +753,6 @@ public: } } } - - juce_free (devs); } return result; @@ -815,7 +780,7 @@ private: bool started; double sampleRate; int bufferSize; - float* audioBuffer; + HeapBlock audioBuffer; int numInputChans, numOutputChans; bool callbacksAllowed; @@ -827,10 +792,8 @@ private: }; int numInputChannelInfos, numOutputChannelInfos; - CallbackDetailsForChannel* inputChannelInfo; - CallbackDetailsForChannel* outputChannelInfo; - float** tempInputBuffers; - float** tempOutputBuffers; + HeapBlock inputChannelInfo, outputChannelInfo; + HeapBlock tempInputBuffers, tempOutputBuffers; CoreAudioInternal (const CoreAudioInternal&); const CoreAudioInternal& operator= (const CoreAudioInternal&); @@ -875,34 +838,24 @@ private: } //============================================================================== - static OSType* getAllDataSourcesForDevice (AudioDeviceID deviceID, const bool input, int& num) + static int getAllDataSourcesForDevice (AudioDeviceID deviceID, const bool input, HeapBlock & types) { - OSType* types = 0; - UInt32 size = 0; - num = 0; - AudioObjectPropertyAddress pa; pa.mSelector = kAudioDevicePropertyDataSources; pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = kAudioObjectPropertyElementMaster; + UInt32 size = 0; if (deviceID != 0 && OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - types = (OSType*) juce_calloc (size); + types.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types))) - { - num = size / sizeof (OSType); - } - else - { - juce_free (types); - types = 0; - } + return size / sizeof (OSType); } - return types; + return 0; } }; @@ -1193,7 +1146,8 @@ public: if (OK (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size))) { - AudioDeviceID* const devs = (AudioDeviceID*) juce_calloc (size); + HeapBlock devs; + devs.calloc (size, 1); if (OK (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs))) { @@ -1231,8 +1185,6 @@ public: alreadyLogged = true; } - - juce_free (devs); } inputDeviceNames.appendNumbersToDuplicates (false, true); @@ -1340,7 +1292,8 @@ private: if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) { - AudioBufferList* const bufList = (AudioBufferList*) juce_calloc (size); + HeapBlock bufList; + bufList.calloc (size, 1); if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) { @@ -1352,8 +1305,6 @@ private: total += b.mNumberChannels; } } - - juce_free (bufList); } return total; diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index bca8f41a77..2f42ee8e25 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -132,7 +132,6 @@ public: CoreGraphicsContext (CGContextRef context_, const float flipHeight_) : context (context_), flipHeight (flipHeight_), - gradientLookupTable (0), numGradientLookupEntries (0) { CGContextRetain (context); @@ -155,7 +154,6 @@ public: CGColorSpaceRelease (rgbColourSpace); CGColorSpaceRelease (greyColourSpace); delete state; - delete gradientLookupTable; } //============================================================================== @@ -183,7 +181,7 @@ public: { const int numRects = clipRegion.getNumRectangles(); - CGRect* const rects = new CGRect [numRects]; + HeapBlock rects (numRects); for (int i = 0; i < numRects; ++i) { const Rectangle& r = clipRegion.getRectangle(i); @@ -191,8 +189,6 @@ public: } CGContextClipToRects (context, rects, numRects); - delete[] rects; - return ! isClipEmpty(); } } @@ -565,7 +561,7 @@ private: SavedState* state; OwnedArray stateStack; - PixelARGB* gradientLookupTable; + HeapBlock gradientLookupTable; int numGradientLookupEntries; static void gradientCallback (void* info, const CGFloat* inData, CGFloat* outData) @@ -584,8 +580,7 @@ private: CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { - delete gradientLookupTable; - gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); + numGradientLookupEntries = gradient.createLookupTable (transform, gradientLookupTable); --numGradientLookupEntries; CGShadingRef result = 0; diff --git a/src/native/mac/juce_mac_CoreMidi.cpp b/src/native/mac/juce_mac_CoreMidi.cpp index 805ceb4735..c32fefd444 100644 --- a/src/native/mac/juce_mac_CoreMidi.cpp +++ b/src/native/mac/juce_mac_CoreMidi.cpp @@ -334,7 +334,8 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) const int maxPacketSize = 256; int pos = 0, bytesLeft = message.getRawDataSize(); const int numPackets = (bytesLeft + maxPacketSize - 1) / maxPacketSize; - MIDIPacketList* const packets = (MIDIPacketList*) juce_malloc (32 * numPackets + message.getRawDataSize()); + HeapBlock packets; + packets.malloc (32 * numPackets + message.getRawDataSize(), 1); packets->numPackets = numPackets; MIDIPacket* p = packets->packet; @@ -353,8 +354,6 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) MIDISend (mpe->port, mpe->endPoint, packets); else MIDIReceived (mpe->endPoint, packets); - - juce_free (packets); } else { diff --git a/src/native/mac/juce_mac_Fonts.mm b/src/native/mac/juce_mac_Fonts.mm index e5a3c0e48b..392ef4d8df 100644 --- a/src/native/mac/juce_mac_Fonts.mm +++ b/src/native/mac/juce_mac_Fonts.mm @@ -201,45 +201,38 @@ public: return 0; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); float x = 0; #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; for (int i = 0; i < length; ++i) x += advances[i].width; - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) for (int i = 0; i < length; ++i) x += advances[i]; - - juce_free (advances); } #endif - juce_free (glyphs); - return x * unitsToHeightScaleFactor; } @@ -251,10 +244,11 @@ public: return; const int length = text.length(); - CGGlyph* const glyphs = createGlyphsForString (text, length); + HeapBlock glyphs; + createGlyphsForString (text, length, glyphs); #if SUPPORT_ONLY_10_4_FONTS - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; int x = 0; @@ -265,12 +259,11 @@ public: resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - juce_free (advances); #else #if SUPPORT_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) { - NSSize* const advances = (NSSize*) juce_malloc (length * sizeof (NSSize)); + HeapBlock advances (length); [nsFont getAdvancements: advances forGlyphs: (NSGlyph*) glyphs count: length]; float x = 0; @@ -280,13 +273,11 @@ public: xOffsets.add (x * unitsToHeightScaleFactor); resultGlyphs.add (((NSGlyph*) glyphs)[i]); } - - juce_free (advances); } else #endif { - int* const advances = (int*) juce_malloc (length * sizeof (int)); + HeapBlock advances (length); if (CGFontGetGlyphAdvances (fontRef, glyphs, length, advances)) { @@ -298,12 +289,8 @@ public: resultGlyphs.add (glyphs[i]); } } - - juce_free (advances); } #endif - - juce_free (glyphs); } bool getOutlineForGlyph (int glyphNumber, Path& path) @@ -369,19 +356,20 @@ private: AffineTransform pathTransform; #endif - CGGlyph* createGlyphsForString (const juce_wchar* const text, const int length) throw() + void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) throw() { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS if (NEW_CGFONT_FUNCTIONS_UNAVAILABLE) #endif { - NSGlyph* const g = (NSGlyph*) juce_malloc (sizeof (NSGlyph) * length); + glyphs.malloc (sizeof (NSGlyph) * length, 1); + NSGlyph* const g = (NSGlyph*) glyphs; for (int i = 0; i < length; ++i) g[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; - return (CGGlyph*) g; + return; } #endif @@ -389,12 +377,10 @@ private: if (charToGlyphMapper == 0) charToGlyphMapper = new CharToGlyphMapper (fontRef); - CGGlyph* const g = (CGGlyph*) juce_malloc (sizeof (CGGlyph) * length); + glyphs.malloc (length); for (int i = 0; i < length; ++i) - g[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); - - return g; + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); #endif } diff --git a/src/native/mac/juce_mac_Strings.mm b/src/native/mac/juce_mac_Strings.mm index 6d2716a616..bfc95d8301 100644 --- a/src/native/mac/juce_mac_Strings.mm +++ b/src/native/mac/juce_mac_Strings.mm @@ -58,20 +58,15 @@ const String PlatformUtilities::cfStringToJuceString (CFStringRef cfString) { #if JUCE_STRINGS_ARE_UNICODE CFRange range = { 0, CFStringGetLength (cfString) }; - UniChar* const u = (UniChar*) juce_malloc (sizeof (UniChar) * (range.length + 1)); - + HeapBlock u (range.length + 1); CFStringGetCharacters (cfString, range, u); u[range.length] = 0; - result = convertUTF16ToString (u); - - juce_free (u); #else const int len = CFStringGetLength (cfString); - char* buffer = (char*) juce_malloc (len + 1); + HeapBlock buffer (len + 1); CFStringGetCString (cfString, buffer, len + 1, CFStringGetSystemEncoding()); result = buffer; - juce_free (buffer); #endif } @@ -83,16 +78,12 @@ CFStringRef PlatformUtilities::juceStringToCFString (const String& s) #if JUCE_STRINGS_ARE_UNICODE const int len = s.length(); const juce_wchar* t = (const juce_wchar*) s; - - UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); + HeapBlock temp (len + 2); for (int i = 0; i <= len; ++i) temp[i] = t[i]; - CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); - juce_free (temp); - - return result; + return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); #else return CFStringCreateWithCString (kCFAllocatorDefault, @@ -126,8 +117,9 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) { const int len = s.length(); - UniChar* const tempIn = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4); - UniChar* const tempOut = (UniChar*) juce_calloc (sizeof (UniChar) * len + 4); + HeapBlock tempIn, tempOut; + tempIn.calloc (len + 2); + tempOut.calloc (len + 2); for (int i = 0; i <= len; ++i) tempIn[i] = s[i]; @@ -153,9 +145,6 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) t[i] = 0; } - juce_free (tempIn); - juce_free (tempOut); - DisposeUnicodeToTextInfo (&conversionInfo); } diff --git a/src/native/windows/juce_win32_ASIO.cpp b/src/native/windows/juce_win32_ASIO.cpp index d15a2b27d0..3328ef850e 100644 --- a/src/native/windows/juce_win32_ASIO.cpp +++ b/src/native/windows/juce_win32_ASIO.cpp @@ -88,7 +88,6 @@ public: optionalDllForDirectLoading (optionalDllForDirectLoading_), currentBitDepth (16), currentSampleRate (0), - tempBuffer (0), isOpen_ (false), isStarted (false), postOutput (true), @@ -115,8 +114,6 @@ public: close(); log ("ASIO - exiting"); removeCurrentDriver(); - - juce_free (tempBuffer); } void updateSampleRates() @@ -451,9 +448,7 @@ public: { buffersCreated = true; - juce_free (tempBuffer); - - tempBuffer = (float*) juce_calloc (totalBuffers * currentBlockSizeSamples * sizeof (float) + 128); + tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32); int n = 0; Array types; @@ -840,7 +835,7 @@ private: bool outputChannelLittleEndian [maxASIOChannels]; WaitableEvent event1; - float* tempBuffer; + HeapBlock tempBuffer; int volatile bufferIndex, numActiveInputChans, numActiveOutputChans; bool isOpen_, isStarted; diff --git a/src/native/windows/juce_win32_AudioCDReader.cpp b/src/native/windows/juce_win32_AudioCDReader.cpp index 949927d26c..b10ac5ce16 100644 --- a/src/native/windows/juce_win32_AudioCDReader.cpp +++ b/src/native/windows/juce_win32_AudioCDReader.cpp @@ -2328,7 +2328,7 @@ bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamples) hr = info->redbook->CreateAudioTrack ((long) numSamples / (bytesPerBlock * 4)); - byte* const buffer = (byte*) juce_malloc (bytesPerBlock); + HeapBlock buffer (bytesPerBlock); AudioSampleBuffer sourceBuffer (2, samplesPerBlock); int samplesDone = 0; @@ -2366,8 +2366,6 @@ bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamples) break; } - juce_free (buffer); - hr = info->redbook->CloseAudioTrack(); delete source; diff --git a/src/native/windows/juce_win32_CameraDevice.cpp b/src/native/windows/juce_win32_CameraDevice.cpp index c84524e6e3..ee91b247ee 100644 --- a/src/native/windows/juce_win32_CameraDevice.cpp +++ b/src/native/windows/juce_win32_CameraDevice.cpp @@ -196,14 +196,14 @@ public: if (getPin (filter, PINDIR_OUTPUT, &pin)) { ComSmartPtr pushSource; - hr = pin->QueryInterface (IID_IAMPushSource, (void**) &pushSource); + HRESULT hr = pin->QueryInterface (IID_IAMPushSource, (void**) &pushSource); if (pushSource != 0) { REFERENCE_TIME latency = 0; - hr = ps->GetLatency (&latency); + hr = pushSource->GetLatency (&latency); - firstRecordedTime -= RelativeTime ((double) latency); + firstRecordedTime = firstRecordedTime - RelativeTime ((double) latency); } } } diff --git a/src/native/windows/juce_win32_DirectSound.cpp b/src/native/windows/juce_win32_DirectSound.cpp index 5bdca4eb9c..0e4a430062 100644 --- a/src/native/windows/juce_win32_DirectSound.cpp +++ b/src/native/windows/juce_win32_DirectSound.cpp @@ -1170,8 +1170,7 @@ private: int64 volatile lastBlockTime; double sampleRate; BitArray enabledInputs, enabledOutputs; - float** inputBuffers; - float** outputBuffers; + HeapBlock inputBuffers, outputBuffers; AudioIODeviceCallback* callback; CriticalSection startStopLock; @@ -1196,15 +1195,13 @@ private: for (i = 0; i < numInputBuffers; ++i) juce_free (inputBuffers[i]); - delete[] inputBuffers; - inputBuffers = 0; + inputBuffers.free(); numInputBuffers = 0; for (i = 0; i < numOutputBuffers; ++i) juce_free (outputBuffers[i]); - delete[] outputBuffers; - outputBuffers = 0; + outputBuffers.free(); numOutputBuffers = 0; } @@ -1526,8 +1523,7 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels, false); numInputBuffers = enabledInputs.countNumberOfSetBits(); - inputBuffers = new float* [numInputBuffers + 2]; - zeromem (inputBuffers, sizeof (float*) * numInputBuffers + 2); + inputBuffers.calloc (numInputBuffers + 2); int i, numIns = 0; for (i = 0; i <= enabledInputs.getHighestBit(); i += 2) @@ -1554,8 +1550,7 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels, false); numOutputBuffers = enabledOutputs.countNumberOfSetBits(); - outputBuffers = new float* [numOutputBuffers + 2]; - zeromem (outputBuffers, sizeof (float*) * numOutputBuffers + 2); + outputBuffers.calloc (numOutputBuffers + 2); int numOuts = 0; for (i = 0; i <= enabledOutputs.getHighestBit(); i += 2) diff --git a/src/native/windows/juce_win32_Files.cpp b/src/native/windows/juce_win32_Files.cpp index 0644f1a30e..184821cfaf 100644 --- a/src/native/windows/juce_win32_Files.cpp +++ b/src/native/windows/juce_win32_Files.cpp @@ -532,7 +532,8 @@ const String File::getVersion() const throw() DWORD handle = 0; DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle); - void* buffer = juce_calloc (bufferSize); + HeapBlock buffer; + buffer.calloc (bufferSize); if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer)) { @@ -549,7 +550,6 @@ const String File::getVersion() const throw() } } - juce_free (buffer); return result; } diff --git a/src/native/windows/juce_win32_Fonts.cpp b/src/native/windows/juce_win32_Fonts.cpp index c2406f686d..92ba3818ae 100644 --- a/src/native/windows/juce_win32_Fonts.cpp +++ b/src/native/windows/juce_win32_Fonts.cpp @@ -128,7 +128,7 @@ class FontDCHolder : private DeletedAtShutdown public: //============================================================================== FontDCHolder() throw() - : dc (0), kps (0), numKPs (0), size (0), + : dc (0), numKPs (0), size (0), bold (false), italic (false) { } @@ -139,7 +139,6 @@ public: { DeleteDC (dc); DeleteObject (fontH); - juce_free (kps); } clearSingletonInstance(); @@ -161,8 +160,7 @@ public: { DeleteDC (dc); DeleteObject (fontH); - juce_free (kps); - kps = 0; + kps.free(); } fontH = 0; @@ -225,7 +223,7 @@ public: if (kps == 0) { numKPs = GetKerningPairs (dc, 0, 0); - kps = (KERNINGPAIR*) juce_calloc (sizeof (KERNINGPAIR) * numKPs); + kps.calloc (numKPs); GetKerningPairs (dc, numKPs, kps); } @@ -239,7 +237,7 @@ private: HFONT fontH; HDC dc; String fontName; - KERNINGPAIR* kps; + HeapBlock kps; int numKPs, size; bool bold, italic; @@ -304,7 +302,7 @@ public: if (bufSize > 0) { - char* const data = (char*) juce_malloc (bufSize); + HeapBlock data (bufSize); GetGlyphOutline (dc, character, GGO_NATIVE, &gm, bufSize, data, &identityMatrix); @@ -372,8 +370,6 @@ public: glyphPath.closeSubPath(); } - - juce_free (data); } addGlyph (character, glyphPath, gm.gmCellIncX / height); diff --git a/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp b/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp index ba5bf4b434..d979df1bf9 100644 --- a/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp +++ b/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp @@ -346,15 +346,11 @@ static CFStringRef juceStringToCFString (const String& s) const int len = s.length(); const juce_wchar* const t = (const juce_wchar*) s; - UniChar* temp = (UniChar*) juce_malloc (sizeof (UniChar) * len + 4); - + HeapBlock temp (len + 2); for (int i = 0; i <= len; ++i) temp[i] = t[i]; - CFStringRef result = CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); - juce_free (temp); - - return result; + return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); } static bool openMovie (QTNewMoviePropertyElement* props, int prop, Movie& movie) diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp index 0a8be4c405..7b0c37acdd 100644 --- a/src/native/windows/juce_win32_Windowing.cpp +++ b/src/native/windows/juce_win32_Windowing.cpp @@ -211,7 +211,6 @@ public: { DeleteDC (hdc); DeleteObject (hBitmap); - imageData = 0; // to stop the base class freeing this } void blitToWindow (HWND hwnd, HDC dc, const bool transparent, @@ -1814,415 +1813,415 @@ public: private: LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam) { + if (isValidPeer (this)) { - if (isValidPeer (this)) + switch (message) { - switch (message) - { - case WM_NCHITTEST: - if (hasTitleBar()) - break; + //============================================================================== + case WM_NCHITTEST: + if ((styleFlags & windowIgnoresMouseClicks) != 0) + return HTTRANSPARENT; + + if (hasTitleBar()) + break; + + return HTCLIENT; - return HTCLIENT; + //============================================================================== + case WM_PAINT: + handlePaintMessage(); + return 0; - //============================================================================== - case WM_PAINT: + case WM_NCPAINT: + if (wParam != 1) handlePaintMessage(); - return 0; - case WM_NCPAINT: - if (wParam != 1) - handlePaintMessage(); + if (hasTitleBar()) + break; - if (hasTitleBar()) - break; + return 0; - return 0; + case WM_ERASEBKGND: + case WM_NCCALCSIZE: + if (hasTitleBar()) + break; - case WM_ERASEBKGND: - case WM_NCCALCSIZE: - if (hasTitleBar()) - break; + return 1; - return 1; + //============================================================================== + case WM_MOUSEMOVE: + doMouseMove (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)); + return 0; - //============================================================================== - case WM_MOUSEMOVE: - doMouseMove (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam)); - return 0; + case WM_MOUSELEAVE: + doMouseExit(); + return 0; - case WM_MOUSELEAVE: - doMouseExit(); - return 0; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + doMouseDown (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); + return 0; - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - doMouseDown (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); - return 0; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + doMouseUp (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); + return 0; - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - doMouseUp (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), wParam); - return 0; + case WM_CAPTURECHANGED: + doCaptureChanged(); + return 0; - case WM_CAPTURECHANGED: - doCaptureChanged(); - return 0; + case WM_NCMOUSEMOVE: + if (hasTitleBar()) + break; - case WM_NCMOUSEMOVE: - if (hasTitleBar()) - break; + return 0; - return 0; + case 0x020A: /* WM_MOUSEWHEEL */ + doMouseWheel (wParam, true); + return 0; - case 0x020A: /* WM_MOUSEWHEEL */ - doMouseWheel (wParam, true); - return 0; + case 0x020E: /* WM_MOUSEHWHEEL */ + doMouseWheel (wParam, false); + return 0; - case 0x020E: /* WM_MOUSEHWHEEL */ - doMouseWheel (wParam, false); - return 0; + //============================================================================== + case WM_WINDOWPOSCHANGING: + if ((styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)) + { + WINDOWPOS* const wp = (WINDOWPOS*) lParam; - //============================================================================== - case WM_WINDOWPOSCHANGING: - if ((styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)) + if ((wp->flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) { - WINDOWPOS* const wp = (WINDOWPOS*) lParam; - - if ((wp->flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) + if (constrainer != 0) { - if (constrainer != 0) - { - const Rectangle current (component->getX() - windowBorder.getLeft(), - component->getY() - windowBorder.getTop(), - component->getWidth() + windowBorder.getLeftAndRight(), - component->getHeight() + windowBorder.getTopAndBottom()); - - constrainer->checkBounds (wp->x, wp->y, wp->cx, wp->cy, - current, - Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(), - wp->y != current.getY() && wp->y + wp->cy == current.getBottom(), - wp->x != current.getX() && wp->x + wp->cx == current.getRight(), - wp->y == current.getY() && wp->y + wp->cy != current.getBottom(), - wp->x == current.getX() && wp->x + wp->cx != current.getRight()); - } + const Rectangle current (component->getX() - windowBorder.getLeft(), + component->getY() - windowBorder.getTop(), + component->getWidth() + windowBorder.getLeftAndRight(), + component->getHeight() + windowBorder.getTopAndBottom()); + + constrainer->checkBounds (wp->x, wp->y, wp->cx, wp->cy, + current, + Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(), + wp->y != current.getY() && wp->y + wp->cy == current.getBottom(), + wp->x != current.getX() && wp->x + wp->cx == current.getRight(), + wp->y == current.getY() && wp->y + wp->cy != current.getBottom(), + wp->x == current.getX() && wp->x + wp->cx != current.getRight()); } } + } - return 0; + return 0; - case WM_WINDOWPOSCHANGED: - handleMovedOrResized(); + case WM_WINDOWPOSCHANGED: + handleMovedOrResized(); - if (dontRepaint) - break; // needed for non-accelerated openGL windows to draw themselves correctly.. - else - return 0; + if (dontRepaint) + break; // needed for non-accelerated openGL windows to draw themselves correctly.. - //============================================================================== - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - if (doKeyDown (wParam)) - return 0; + return 0; - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - if (doKeyUp (wParam)) - return 0; - - break; + //============================================================================== + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (doKeyDown (wParam)) + return 0; - case WM_CHAR: - if (doKeyChar ((int) wParam, lParam)) - return 0; + break; - break; + case WM_KEYUP: + case WM_SYSKEYUP: + if (doKeyUp (wParam)) + return 0; - case WM_APPCOMMAND: - if (doAppCommand (lParam)) - return TRUE; + break; - break; + case WM_CHAR: + if (doKeyChar ((int) wParam, lParam)) + return 0; - //============================================================================== - case WM_SETFOCUS: - updateKeyModifiers(); - handleFocusGain(); - break; + break; - case WM_KILLFOCUS: - if (hasCreatedCaret) - { - hasCreatedCaret = false; - DestroyCaret(); - } + case WM_APPCOMMAND: + if (doAppCommand (lParam)) + return TRUE; - handleFocusLoss(); - break; + break; - case WM_ACTIVATEAPP: - // Windows does weird things to process priority when you swap apps, - // so this forces an update when the app is brought to the front - if (wParam != FALSE) - juce_repeatLastProcessPriority(); - else - Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus + //============================================================================== + case WM_SETFOCUS: + updateKeyModifiers(); + handleFocusGain(); + break; - juce_CheckCurrentlyFocusedTopLevelWindow(); - modifiersAtLastCallback = -1; - return 0; + case WM_KILLFOCUS: + if (hasCreatedCaret) + { + hasCreatedCaret = false; + DestroyCaret(); + } - case WM_ACTIVATE: - if (LOWORD (wParam) == WA_ACTIVE || LOWORD (wParam) == WA_CLICKACTIVE) - { - modifiersAtLastCallback = -1; - updateKeyModifiers(); + handleFocusLoss(); + break; - if (isMinimised()) - { - component->repaint(); - handleMovedOrResized(); + case WM_ACTIVATEAPP: + // Windows does weird things to process priority when you swap apps, + // so this forces an update when the app is brought to the front + if (wParam != FALSE) + juce_repeatLastProcessPriority(); + else + Desktop::getInstance().setKioskModeComponent (0); // turn kiosk mode off if we lose focus - if (! isValidMessageListener()) - return 0; - } + juce_CheckCurrentlyFocusedTopLevelWindow(); + modifiersAtLastCallback = -1; + return 0; - if (LOWORD (wParam) == WA_CLICKACTIVE - && component->isCurrentlyBlockedByAnotherModalComponent()) - { - int mx, my; - component->getMouseXYRelative (mx, my); - Component* const underMouse = component->getComponentAt (mx, my); + case WM_ACTIVATE: + if (LOWORD (wParam) == WA_ACTIVE || LOWORD (wParam) == WA_CLICKACTIVE) + { + modifiersAtLastCallback = -1; + updateKeyModifiers(); - if (underMouse != 0 && underMouse->isCurrentlyBlockedByAnotherModalComponent()) - Component::getCurrentlyModalComponent()->inputAttemptWhenModal(); + if (isMinimised()) + { + component->repaint(); + handleMovedOrResized(); + if (! isValidMessageListener()) return 0; - } + } - handleBroughtToFront(); + if (LOWORD (wParam) == WA_CLICKACTIVE + && component->isCurrentlyBlockedByAnotherModalComponent()) + { + int mx, my; + component->getMouseXYRelative (mx, my); + Component* const underMouse = component->getComponentAt (mx, my); - if (component->isCurrentlyBlockedByAnotherModalComponent()) - Component::getCurrentlyModalComponent()->toFront (true); + if (underMouse != 0 && underMouse->isCurrentlyBlockedByAnotherModalComponent()) + Component::getCurrentlyModalComponent()->inputAttemptWhenModal(); return 0; } - break; + handleBroughtToFront(); - case WM_NCACTIVATE: - // while a temporary window is being shown, prevent Windows from deactivating the - // title bars of our main windows. - if (wParam == 0 && ! shouldDeactivateTitleBar) - wParam = TRUE; // change this and let it get passed to the DefWindowProc. + if (component->isCurrentlyBlockedByAnotherModalComponent()) + Component::getCurrentlyModalComponent()->toFront (true); - break; + return 0; + } - case WM_MOUSEACTIVATE: - if (! component->getMouseClickGrabsKeyboardFocus()) - return MA_NOACTIVATE; + break; - break; + case WM_NCACTIVATE: + // while a temporary window is being shown, prevent Windows from deactivating the + // title bars of our main windows. + if (wParam == 0 && ! shouldDeactivateTitleBar) + wParam = TRUE; // change this and let it get passed to the DefWindowProc. - case WM_SHOWWINDOW: - if (wParam != 0) - handleBroughtToFront(); + break; - break; + case WM_MOUSEACTIVATE: + if (! component->getMouseClickGrabsKeyboardFocus()) + return MA_NOACTIVATE; - case WM_CLOSE: - if (! component->isCurrentlyBlockedByAnotherModalComponent()) - handleUserClosingWindow(); + break; - return 0; + case WM_SHOWWINDOW: + if (wParam != 0) + handleBroughtToFront(); - case WM_QUIT: - if (JUCEApplication::getInstance() != 0) - JUCEApplication::getInstance()->systemRequestedQuit(); - return 0; + break; - case WM_QUERYENDSESSION: - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->systemRequestedQuit(); - return MessageManager::getInstance()->hasStopMessageBeenSent(); - } - return TRUE; + case WM_CLOSE: + if (! component->isCurrentlyBlockedByAnotherModalComponent()) + handleUserClosingWindow(); - //============================================================================== - case WM_TRAYNOTIFY: - if (component->isCurrentlyBlockedByAnotherModalComponent()) + return 0; + + case WM_QUIT: + if (JUCEApplication::getInstance() != 0) + JUCEApplication::getInstance()->systemRequestedQuit(); + return 0; + + case WM_QUERYENDSESSION: + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + return MessageManager::getInstance()->hasStopMessageBeenSent(); + } + return TRUE; + + //============================================================================== + case WM_TRAYNOTIFY: + if (component->isCurrentlyBlockedByAnotherModalComponent()) + { + if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN + || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) { - if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN - || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) - { - Component* const current = Component::getCurrentlyModalComponent(); + Component* const current = Component::getCurrentlyModalComponent(); - if (current != 0) - current->inputAttemptWhenModal(); - } + if (current != 0) + current->inputAttemptWhenModal(); } - else - { - const int oldModifiers = currentModifiers; + } + else + { + const int oldModifiers = currentModifiers; - MouseEvent e (0, 0, ModifierKeys::getCurrentModifiersRealtime(), component, - getMouseEventTime(), 0, 0, getMouseEventTime(), 1, false); + MouseEvent e (0, 0, ModifierKeys::getCurrentModifiersRealtime(), component, + getMouseEventTime(), 0, 0, getMouseEventTime(), 1, false); - if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK) - e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::leftButtonModifier); - else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK) - e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::rightButtonModifier); + if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK) + e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::leftButtonModifier); + else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK) + e.mods = ModifierKeys (e.mods.getRawFlags() | ModifierKeys::rightButtonModifier); - if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) - { - SetFocus (hwnd); - SetForegroundWindow (hwnd); + if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN) + { + SetFocus (hwnd); + SetForegroundWindow (hwnd); - component->mouseDown (e); - } - else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) - { - e.mods = ModifierKeys (oldModifiers); - component->mouseUp (e); - } - else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) - { - e.mods = ModifierKeys (oldModifiers); - component->mouseDoubleClick (e); - } - else if (lParam == WM_MOUSEMOVE) - { - component->mouseMove (e); - } + component->mouseDown (e); } + else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP) + { + e.mods = ModifierKeys (oldModifiers); + component->mouseUp (e); + } + else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK) + { + e.mods = ModifierKeys (oldModifiers); + component->mouseDoubleClick (e); + } + else if (lParam == WM_MOUSEMOVE) + { + component->mouseMove (e); + } + } - break; + break; - //============================================================================== - case WM_SYNCPAINT: - return 0; + //============================================================================== + case WM_SYNCPAINT: + return 0; - case WM_PALETTECHANGED: - InvalidateRect (h, 0, 0); - break; + case WM_PALETTECHANGED: + InvalidateRect (h, 0, 0); + break; - case WM_DISPLAYCHANGE: - InvalidateRect (h, 0, 0); - createPaletteIfNeeded = true; - // intentional fall-through... - case WM_SETTINGCHANGE: // note the fall-through in the previous case! - doSettingChange(); - break; + case WM_DISPLAYCHANGE: + InvalidateRect (h, 0, 0); + createPaletteIfNeeded = true; + // intentional fall-through... + case WM_SETTINGCHANGE: // note the fall-through in the previous case! + doSettingChange(); + break; - case WM_INITMENU: - if (! hasTitleBar()) + case WM_INITMENU: + if (! hasTitleBar()) + { + if (isFullScreen()) { - if (isFullScreen()) - { - EnableMenuItem ((HMENU) wParam, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); - EnableMenuItem ((HMENU) wParam, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); - } - else if (! isMinimised()) - { - EnableMenuItem ((HMENU) wParam, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); - } + EnableMenuItem ((HMENU) wParam, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); + EnableMenuItem ((HMENU) wParam, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); } - break; - - case WM_SYSCOMMAND: - switch (wParam & 0xfff0) + else if (! isMinimised()) { - case SC_CLOSE: - if (sendInputAttemptWhenModalMessage()) - return 0; + EnableMenuItem ((HMENU) wParam, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); + } + } + break; - if (hasTitleBar()) - { - PostMessage (h, WM_CLOSE, 0, 0); - return 0; - } - break; + case WM_SYSCOMMAND: + switch (wParam & 0xfff0) + { + case SC_CLOSE: + if (sendInputAttemptWhenModalMessage()) + return 0; - case SC_KEYMENU: - // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very - // obscure situations that can arise if a modal loop is started from an alt-key - // keypress). + if (hasTitleBar()) + { + PostMessage (h, WM_CLOSE, 0, 0); + return 0; + } + break; - if (hasTitleBar() && h == GetCapture()) - ReleaseCapture(); + case SC_KEYMENU: + // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very + // obscure situations that can arise if a modal loop is started from an alt-key + // keypress). - break; + if (hasTitleBar() && h == GetCapture()) + ReleaseCapture(); - case SC_MAXIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + break; - setFullScreen (true); + case SC_MAXIMIZE: + if (sendInputAttemptWhenModalMessage()) return 0; - case SC_MINIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + setFullScreen (true); + return 0; - if (! hasTitleBar()) - { - setMinimised (true); - return 0; - } - break; + case SC_MINIMIZE: + if (sendInputAttemptWhenModalMessage()) + return 0; - case SC_RESTORE: - if (sendInputAttemptWhenModalMessage()) - return 0; + if (! hasTitleBar()) + { + setMinimised (true); + return 0; + } + break; - if (hasTitleBar()) - { - if (isFullScreen()) - { - setFullScreen (false); - return 0; - } - } - else - { - if (isMinimised()) - setMinimised (false); - else if (isFullScreen()) - setFullScreen (false); + case SC_RESTORE: + if (sendInputAttemptWhenModalMessage()) + return 0; + if (hasTitleBar()) + { + if (isFullScreen()) + { + setFullScreen (false); return 0; } + } + else + { + if (isMinimised()) + setMinimised (false); + else if (isFullScreen()) + setFullScreen (false); - break; + return 0; } break; + } - case WM_NCLBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCMBUTTONDOWN: - sendInputAttemptWhenModalMessage(); - break; + break; - //case WM_IME_STARTCOMPOSITION; - // return 0; + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: + sendInputAttemptWhenModalMessage(); + break; - case WM_GETDLGCODE: - return DLGC_WANTALLKEYS; + //case WM_IME_STARTCOMPOSITION; + // return 0; - default: - break; - } + case WM_GETDLGCODE: + return DLGC_WANTALLKEYS; + + default: + break; } } - // (the message manager lock exits before calling this, to avoid deadlocks if - // this calls into non-juce windows) return DefWindowProc (h, message, wParam, lParam); } @@ -2635,8 +2634,9 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot else { const int stride = (maxW + 7) >> 3; - uint8* const andPlane = (uint8*) juce_calloc (stride * maxH); - uint8* const xorPlane = (uint8*) juce_calloc (stride * maxH); + HeapBlock andPlane, xorPlane; + andPlane.calloc (stride * maxH); + xorPlane.calloc (stride * maxH); int index = 0; for (int y = 0; y < maxH; ++y) @@ -2657,9 +2657,6 @@ void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hot } cursorH = CreateCursor (0, hotspotX, hotspotY, maxW, maxH, andPlane, xorPlane); - - juce_free (andPlane); - juce_free (xorPlane); } delete newIm; diff --git a/src/text/juce_StringArray.cpp b/src/text/juce_StringArray.cpp index b6d4810066..4b8ae6ddbb 100644 --- a/src/text/juce_StringArray.cpp +++ b/src/text/juce_StringArray.cpp @@ -93,13 +93,8 @@ bool StringArray::operator== (const StringArray& other) const throw() return false; for (int i = size(); --i >= 0;) - { - if (*(String*) other.strings.getUnchecked(i) - != *(String*) strings.getUnchecked(i)) - { + if (*other.strings.getUnchecked(i) != *strings.getUnchecked(i)) return false; - } - } return true; } @@ -111,19 +106,13 @@ bool StringArray::operator!= (const StringArray& other) const throw() void StringArray::clear() throw() { - for (int i = size(); --i >= 0;) - { - String* const s = (String*) strings.getUnchecked(i); - delete s; - } - strings.clear(); } const String& StringArray::operator[] (const int index) const throw() { if (((unsigned int) index) < (unsigned int) strings.size()) - return *(const String*) (strings.getUnchecked (index)); + return *strings.getUnchecked (index); return String::empty; } @@ -160,22 +149,18 @@ void StringArray::addArray (const StringArray& otherArray, numElementsToAdd = otherArray.size() - startIndex; while (--numElementsToAdd >= 0) - strings.add (new String (*(const String*) otherArray.strings.getUnchecked (startIndex++))); + strings.add (new String (*otherArray.strings.getUnchecked (startIndex++))); } void StringArray::set (const int index, const String& newString) throw() { - String* const s = (String*) strings [index]; + String* const s = strings [index]; if (s != 0) - { *s = newString; - } else if (index >= 0) - { add (newString); - } } bool StringArray::contains (const String& stringToLookFor, @@ -184,13 +169,13 @@ bool StringArray::contains (const String& stringToLookFor, if (ignoreCase) { for (int i = size(); --i >= 0;) - if (stringToLookFor.equalsIgnoreCase (*(const String*)(strings.getUnchecked(i)))) + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToLookFor)) return true; } else { for (int i = size(); --i >= 0;) - if (stringToLookFor == *(const String*)(strings.getUnchecked(i))) + if (stringToLookFor == *strings.getUnchecked(i)) return true; } @@ -210,7 +195,7 @@ int StringArray::indexOf (const String& stringToLookFor, { while (i < numElements) { - if (stringToLookFor.equalsIgnoreCase (*(const String*) strings.getUnchecked (i))) + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToLookFor)) return i; ++i; @@ -220,7 +205,7 @@ int StringArray::indexOf (const String& stringToLookFor, { while (i < numElements) { - if (stringToLookFor == *(const String*) strings.getUnchecked (i)) + if (stringToLookFor == *strings.getUnchecked (i)) return i; ++i; @@ -233,13 +218,7 @@ int StringArray::indexOf (const String& stringToLookFor, //============================================================================== void StringArray::remove (const int index) throw() { - String* const s = (String*) strings [index]; - - if (s != 0) - { - strings.remove (index); - delete s; - } + strings.remove (index); } void StringArray::removeString (const String& stringToRemove, @@ -248,14 +227,14 @@ void StringArray::removeString (const String& stringToRemove, if (ignoreCase) { for (int i = size(); --i >= 0;) - if (stringToRemove.equalsIgnoreCase (*(const String*) strings.getUnchecked (i))) - remove (i); + if (strings.getUnchecked(i)->equalsIgnoreCase (stringToRemove)) + strings.remove (i); } else { for (int i = size(); --i >= 0;) - if (stringToRemove == *(const String*) strings.getUnchecked (i)) - remove (i); + if (stringToRemove == *strings.getUnchecked (i)) + strings.remove (i); } } @@ -265,14 +244,14 @@ void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) throw( if (removeWhitespaceStrings) { for (int i = size(); --i >= 0;) - if (! ((const String*) strings.getUnchecked(i))->containsNonWhitespaceChars()) - remove (i); + if (! strings.getUnchecked(i)->containsNonWhitespaceChars()) + strings.remove (i); } else { for (int i = size(); --i >= 0;) - if (((const String*) strings.getUnchecked(i))->isEmpty()) - remove (i); + if (strings.getUnchecked(i)->isEmpty()) + strings.remove (i); } } @@ -280,7 +259,7 @@ void StringArray::trim() throw() { for (int i = size(); --i >= 0;) { - String& s = *(String*) strings.getUnchecked(i); + String& s = *strings.getUnchecked(i); s = s.trim(); } } @@ -339,13 +318,13 @@ const String StringArray::joinIntoString (const String& separator, return String::empty; if (start == last - 1) - return *(const String*) strings.getUnchecked (start); + return *strings.getUnchecked (start); const int separatorLen = separator.length(); int charsNeeded = separatorLen * (last - start - 1); for (int i = start; i < last; ++i) - charsNeeded += ((const String*) strings.getUnchecked(i))->length(); + charsNeeded += strings.getUnchecked(i)->length(); String result; result.preallocateStorage (charsNeeded); @@ -354,7 +333,7 @@ const String StringArray::joinIntoString (const String& separator, while (start < last) { - const String& s = *(const String*) strings.getUnchecked (start); + const String& s = *strings.getUnchecked (start); const int len = s.length(); if (len > 0) @@ -520,7 +499,7 @@ void StringArray::removeDuplicates (const bool ignoreCase) throw() { for (int i = 0; i < size() - 1; ++i) { - const String& s = *(String*) strings.getUnchecked(i); + const String& s = *strings.getUnchecked(i); int nextIndex = i + 1; @@ -531,7 +510,7 @@ void StringArray::removeDuplicates (const bool ignoreCase) throw() if (nextIndex < 0) break; - remove (nextIndex); + strings.remove (nextIndex); } } } @@ -543,7 +522,7 @@ void StringArray::appendNumbersToDuplicates (const bool ignoreCase, { for (int i = 0; i < size() - 1; ++i) { - String& s = *(String*) strings.getUnchecked(i); + String& s = *strings.getUnchecked(i); int nextIndex = indexOf (s, ignoreCase, i + 1); diff --git a/src/text/juce_StringArray.h b/src/text/juce_StringArray.h index 631c80c7d7..191e7f938c 100644 --- a/src/text/juce_StringArray.h +++ b/src/text/juce_StringArray.h @@ -27,7 +27,7 @@ #define __JUCE_STRINGARRAY_JUCEHEADER__ #include "juce_String.h" -#include "../containers/juce_VoidArray.h" +#include "../containers/juce_OwnedArray.h" #ifndef DOXYGEN // (used in StringArray::appendNumbersToDuplicates) @@ -325,7 +325,7 @@ public: juce_UseDebuggingNewOperator private: - VoidArray strings; + OwnedArray strings; }; diff --git a/src/text/juce_XmlElement.cpp b/src/text/juce_XmlElement.cpp index 7456d737d6..5e24e4fb80 100644 --- a/src/text/juce_XmlElement.cpp +++ b/src/text/juce_XmlElement.cpp @@ -1073,20 +1073,15 @@ XmlElement* XmlElement::findParentElementOf (const XmlElement* const elementToLo return 0; } -XmlElement** XmlElement::getChildElementsAsArray (const int num) const throw() +void XmlElement::getChildElementsAsArray (XmlElement** elems) const throw() { - XmlElement** const elems = new XmlElement* [num]; - XmlElement* e = firstChildElement; - int i = 0; while (e != 0) { - elems [i++] = e; + *elems++ = e; e = e->nextElement; } - - return elems; } void XmlElement::reorderChildElements (XmlElement** const elems, const int num) throw() diff --git a/src/text/juce_XmlElement.h b/src/text/juce_XmlElement.h index 62e9f52374..6c31aa63a1 100644 --- a/src/text/juce_XmlElement.h +++ b/src/text/juce_XmlElement.h @@ -594,10 +594,10 @@ public: if (num > 1) { - XmlElement** const elems = getChildElementsAsArray (num); - sortArray (comparator, elems, 0, num - 1, retainOrderOfEquivalentItems); + HeapBlock elems (num); + getChildElementsAsArray (elems); + sortArray (comparator, (XmlElement**) elems, 0, num - 1, retainOrderOfEquivalentItems); reorderChildElements (elems, num); - delete[] elems; } } @@ -706,7 +706,7 @@ private: const int indentationLevel, const int lineWrapLength) const throw(); - XmlElement** getChildElementsAsArray (const int) const throw(); + void getChildElementsAsArray (XmlElement**) const throw(); void reorderChildElements (XmlElement** const, const int) throw(); }; diff --git a/src/threads/juce_ThreadPool.cpp b/src/threads/juce_ThreadPool.cpp index b18e4bd6c7..39ab22c883 100644 --- a/src/threads/juce_ThreadPool.cpp +++ b/src/threads/juce_ThreadPool.cpp @@ -106,7 +106,7 @@ ThreadPool::ThreadPool (const int numThreads_, { jassert (numThreads_ > 0); // not much point having one of these with no threads in it. - threads = (Thread**) juce_calloc (sizeof (Thread*) * numThreads); + threads.calloc (numThreads); for (int i = numThreads; --i >= 0;) threads[i] = new ThreadPoolThread (*this); @@ -129,8 +129,6 @@ ThreadPool::~ThreadPool() threads[i]->stopThread (500); delete threads[i]; } - - juce_free (threads); } void ThreadPool::addJob (ThreadPoolJob* const job) diff --git a/src/threads/juce_ThreadPool.h b/src/threads/juce_ThreadPool.h index bc81cfbd6e..bf421e0b8a 100644 --- a/src/threads/juce_ThreadPool.h +++ b/src/threads/juce_ThreadPool.h @@ -30,6 +30,7 @@ #include "juce_ScopedLock.h" #include "../text/juce_StringArray.h" #include "../containers/juce_VoidArray.h" +#include "../containers/juce_HeapBlock.h" class ThreadPool; class ThreadPoolThread; @@ -299,7 +300,7 @@ public: private: const int numThreads, threadStopTimeout; int priority; - Thread** threads; + HeapBlock threads; VoidArray jobs; CriticalSection lock; diff --git a/src/utilities/juce_UndoManager.h b/src/utilities/juce_UndoManager.h index 45739ae085..62743274cc 100644 --- a/src/utilities/juce_UndoManager.h +++ b/src/utilities/juce_UndoManager.h @@ -28,6 +28,7 @@ #include "../text/juce_String.h" #include "../containers/juce_OwnedArray.h" +#include "../containers/juce_Array.h" #include "../text/juce_StringArray.h" #include "../events/juce_ChangeBroadcaster.h" #include "juce_UndoableAction.h"