diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index 9b2a4a80dd..c4ae48bbd7 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -682,6 +682,7 @@ 15C6FD019B274AA51B4E2D76 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_KeyPressMappingSet.h; path = ../../src/gui/components/keyboard/juce_KeyPressMappingSet.h; sourceTree = SOURCE_ROOT; }; B1E8FF009812F29C2620E6BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModifierKeys.cpp; path = ../../src/gui/components/keyboard/juce_ModifierKeys.cpp; sourceTree = SOURCE_ROOT; }; FAEEA3536AD17B2667A1BB94 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModifierKeys.h; path = ../../src/gui/components/keyboard/juce_ModifierKeys.h; sourceTree = SOURCE_ROOT; }; + D64DD9F41E4598606855DFCF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextEditorKeyMapper.h; path = ../../src/gui/components/keyboard/juce_TextEditorKeyMapper.h; sourceTree = SOURCE_ROOT; }; 7356F5E93CEA4D472D83D8E5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextInputTarget.h; path = ../../src/gui/components/keyboard/juce_TextInputTarget.h; sourceTree = SOURCE_ROOT; }; 921B616E2229AEB6390D2B57 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ComponentAnimator.cpp; path = ../../src/gui/components/layout/juce_ComponentAnimator.cpp; sourceTree = SOURCE_ROOT; }; FE1072B5FB77E8FEE1BEBDFE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentAnimator.h; path = ../../src/gui/components/layout/juce_ComponentAnimator.h; sourceTree = SOURCE_ROOT; }; @@ -1447,6 +1448,7 @@ 15C6FD019B274AA51B4E2D76, B1E8FF009812F29C2620E6BB, FAEEA3536AD17B2667A1BB94, + D64DD9F41E4598606855DFCF, 7356F5E93CEA4D472D83D8E5 ); name = keyboard; sourceTree = ""; }; D75AAB3AB61247E962C00692 = { isa = PBXGroup; children = ( 921B616E2229AEB6390D2B57, diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index 5df9a83f91..2bbc5576c3 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -532,6 +532,7 @@ + diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index 45910eb4bb..329ec278e8 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -532,6 +532,7 @@ + diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index 9de9b7197c..d5471a33f3 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -534,6 +534,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index 7e2a18216a..42fed03f62 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -626,6 +626,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index a948be7877..ce55c9390f 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -1809,6 +1809,9 @@ Juce\Source\gui\components\keyboard + + Juce\Source\gui\components\keyboard + Juce\Source\gui\components\keyboard diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj index ac113b91d4..45e07ccc02 100644 --- a/Builds/iOS/Juce.xcodeproj/project.pbxproj +++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj @@ -682,6 +682,7 @@ 15C6FD019B274AA51B4E2D76 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_KeyPressMappingSet.h; path = ../../src/gui/components/keyboard/juce_KeyPressMappingSet.h; sourceTree = SOURCE_ROOT; }; B1E8FF009812F29C2620E6BB = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModifierKeys.cpp; path = ../../src/gui/components/keyboard/juce_ModifierKeys.cpp; sourceTree = SOURCE_ROOT; }; FAEEA3536AD17B2667A1BB94 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModifierKeys.h; path = ../../src/gui/components/keyboard/juce_ModifierKeys.h; sourceTree = SOURCE_ROOT; }; + D64DD9F41E4598606855DFCF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextEditorKeyMapper.h; path = ../../src/gui/components/keyboard/juce_TextEditorKeyMapper.h; sourceTree = SOURCE_ROOT; }; 7356F5E93CEA4D472D83D8E5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_TextInputTarget.h; path = ../../src/gui/components/keyboard/juce_TextInputTarget.h; sourceTree = SOURCE_ROOT; }; 921B616E2229AEB6390D2B57 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ComponentAnimator.cpp; path = ../../src/gui/components/layout/juce_ComponentAnimator.cpp; sourceTree = SOURCE_ROOT; }; FE1072B5FB77E8FEE1BEBDFE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentAnimator.h; path = ../../src/gui/components/layout/juce_ComponentAnimator.h; sourceTree = SOURCE_ROOT; }; @@ -1447,6 +1448,7 @@ 15C6FD019B274AA51B4E2D76, B1E8FF009812F29C2620E6BB, FAEEA3536AD17B2667A1BB94, + D64DD9F41E4598606855DFCF, 7356F5E93CEA4D472D83D8E5 ); name = keyboard; sourceTree = ""; }; D75AAB3AB61247E962C00692 = { isa = PBXGroup; children = ( 921B616E2229AEB6390D2B57, diff --git a/Juce.jucer b/Juce.jucer index 1093348edc..26237a2666 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -713,6 +713,8 @@ file="src/gui/components/keyboard/juce_ModifierKeys.cpp"/> + diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index bd10135eec..b44613d1ce 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -1287,7 +1287,7 @@ FileLogger::FileLogger (const File& logFile_, << welcomeMessage << newLine << "Log started: " << Time::getCurrentTime().toString (true, true) << newLine; - logMessage (welcome); + FileLogger::logMessage (welcome); } FileLogger::~FileLogger() @@ -3253,91 +3253,79 @@ bool BigInteger::operator<= (const BigInteger& other) const noexcept { return co bool BigInteger::operator> (const BigInteger& other) const noexcept { return compare (other) > 0; } bool BigInteger::operator>= (const BigInteger& other) const noexcept { return compare (other) >= 0; } -void BigInteger::shiftBits (int bits, const int startBit) +void BigInteger::shiftLeft (int bits, const int startBit) { - if (highestBit < 0) - return; - if (startBit > 0) { - if (bits < 0) - { - // right shift - for (int i = startBit; i <= highestBit; ++i) - setBit (i, operator[] (i - bits)); + for (int i = highestBit + 1; --i >= startBit;) + setBit (i + bits, operator[] (i)); - highestBit = getHighestBit(); - } - else if (bits > 0) - { - // left shift - for (int i = highestBit + 1; --i >= startBit;) - setBit (i + bits, operator[] (i)); - - while (--bits >= 0) - clearBit (bits + startBit); - } + while (--bits >= 0) + clearBit (bits + startBit); } else { - if (bits < 0) + ensureSize (bitToIndex (highestBit + bits) + 1); + + const int wordsToMove = bitToIndex (bits); + int top = 1 + bitToIndex (highestBit); + highestBit += bits; + + if (wordsToMove > 0) { - // right shift - bits = -bits; + int i; + for (i = top; --i >= 0;) + values [i + wordsToMove] = values [i]; - if (bits > highestBit) - { - clear(); - } - else - { - const int wordsToMove = bitToIndex (bits); - int top = 1 + bitToIndex (highestBit) - wordsToMove; - highestBit -= bits; + for (i = 0; i < wordsToMove; ++i) + values [i] = 0; - if (wordsToMove > 0) - { - int i; - for (i = 0; i < top; ++i) - values [i] = values [i + wordsToMove]; + bits &= 31; + } - for (i = 0; i < wordsToMove; ++i) - values [top + i] = 0; + if (bits != 0) + { + const int invBits = 32 - bits; - bits &= 31; - } + for (int i = top + 1 + wordsToMove; --i > wordsToMove;) + values[i] = (values[i] << bits) | (values [i - 1] >> invBits); - if (bits != 0) - { - const int invBits = 32 - bits; + values [wordsToMove] = values [wordsToMove] << bits; + } - --top; - for (int i = 0; i < top; ++i) - values[i] = (values[i] >> bits) | (values [i + 1] << invBits); + highestBit = getHighestBit(); + } +} - values[top] = (values[top] >> bits); - } +void BigInteger::shiftRight (int bits, const int startBit) +{ + if (startBit > 0) + { + for (int i = startBit; i <= highestBit; ++i) + setBit (i, operator[] (i + bits)); - highestBit = getHighestBit(); - } + highestBit = getHighestBit(); + } + else + { + if (bits > highestBit) + { + clear(); } - else if (bits > 0) + else { - // left shift - ensureSize (bitToIndex (highestBit + bits) + 1); - const int wordsToMove = bitToIndex (bits); - int top = 1 + bitToIndex (highestBit); - highestBit += bits; + int top = 1 + bitToIndex (highestBit) - wordsToMove; + highestBit -= bits; if (wordsToMove > 0) { int i; - for (i = top; --i >= 0;) - values [i + wordsToMove] = values [i]; + for (i = 0; i < top; ++i) + values [i] = values [i + wordsToMove]; for (i = 0; i < wordsToMove; ++i) - values [i] = 0; + values [top + i] = 0; bits &= 31; } @@ -3346,10 +3334,11 @@ void BigInteger::shiftBits (int bits, const int startBit) { const int invBits = 32 - bits; - for (int i = top + 1 + wordsToMove; --i > wordsToMove;) - values[i] = (values[i] << bits) | (values [i - 1] >> invBits); + --top; + for (int i = 0; i < top; ++i) + values[i] = (values[i] >> bits) | (values [i + 1] << invBits); - values [wordsToMove] = values [wordsToMove] << bits; + values[top] = (values[top] >> bits); } highestBit = getHighestBit(); @@ -3357,6 +3346,17 @@ void BigInteger::shiftBits (int bits, const int startBit) } } +void BigInteger::shiftBits (int bits, const int startBit) +{ + if (highestBit >= 0) + { + if (bits < 0) + shiftRight (-bits, startBit); + else if (bits > 0) + shiftLeft (bits, startBit); + } +} + const BigInteger BigInteger::simpleGCD (BigInteger* m, BigInteger* n) { while (! m->isZero()) @@ -4529,16 +4529,16 @@ void var::swapWith (var& other) noexcept std::swap (value, other.value); } -var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; } -var& var::operator= (const int newValue) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = newValue; return *this; } -var& var::operator= (const int64 newValue) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = newValue; return *this; } -var& var::operator= (const bool newValue) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = newValue; return *this; } -var& var::operator= (const double newValue) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = newValue; return *this; } -var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } -var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } -var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } -var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } -var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } +const var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; } +const var& var::operator= (const int newValue) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = newValue; return *this; } +const var& var::operator= (const int64 newValue) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = newValue; return *this; } +const var& var::operator= (const bool newValue) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = newValue; return *this; } +const var& var::operator= (const double newValue) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = newValue; return *this; } +const var& var::operator= (const char* const newValue) { var v (newValue); swapWith (v); return *this; } +const var& var::operator= (const wchar_t* const newValue) { var v (newValue); swapWith (v); return *this; } +const var& var::operator= (const String& newValue) { var v (newValue); swapWith (v); return *this; } +const var& var::operator= (ReferenceCountedObject* newValue) { var v (newValue); swapWith (v); return *this; } +const var& var::operator= (MethodFunction newValue) { var v (newValue); swapWith (v); return *this; } bool var::equals (const var& other) const noexcept { @@ -8627,7 +8627,8 @@ FileOutputStream::FileOutputStream (const File& f, const int bufferSize_) FileOutputStream::~FileOutputStream() { - flush(); + flushBuffer(); + flushInternal(); closeHandle(); } @@ -8640,21 +8641,29 @@ bool FileOutputStream::setPosition (int64 newPosition) { if (newPosition != currentPosition) { - flush(); + flushBuffer(); currentPosition = juce_fileSetPosition (fileHandle, newPosition); } return newPosition == currentPosition; } -void FileOutputStream::flush() +bool FileOutputStream::flushBuffer() { + bool ok = true; + if (bytesInBuffer > 0) { - writeInternal (buffer, bytesInBuffer); + ok = (writeInternal (buffer, bytesInBuffer) == bytesInBuffer); bytesInBuffer = 0; } + return ok; +} + +void FileOutputStream::flush() +{ + flushBuffer(); flushInternal(); } @@ -8668,15 +8677,8 @@ bool FileOutputStream::write (const void* const src, const int numBytes) } else { - if (bytesInBuffer > 0) - { - // flush the reservoir - const bool wroteOk = (writeInternal (buffer, bytesInBuffer) == bytesInBuffer); - bytesInBuffer = 0; - - if (! wroteOk) - return false; - } + if (! flushBuffer()) + return false; if (numBytes < bufferSize) { @@ -10415,10 +10417,15 @@ MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, MemoryOutputStream::~MemoryOutputStream() { - flush(); + trimExternalBlockSize(); } void MemoryOutputStream::flush() +{ + trimExternalBlockSize(); +} + +void MemoryOutputStream::trimExternalBlockSize() { if (&data != &internalBlock) data.setSize (size, false); @@ -10526,7 +10533,7 @@ SubregionStream::SubregionStream (InputStream* const sourceStream, startPositionInSourceStream (startPositionInSourceStream_), lengthOfSourceStream (lengthOfSourceStream_) { - setPosition (0); + SubregionStream::setPosition (0); } SubregionStream::~SubregionStream() @@ -15123,7 +15130,7 @@ void XmlDocument::readChildElements (XmlElement* parent) if (n != nullptr) childAppender.append (n); else - return; + break; } } else // must be a character block @@ -21630,7 +21637,7 @@ public: isRunning = false; timeSliceThread.removeTimeSliceClient (this); - while (useTimeSlice() == 0) + while (writePendingData() == 0) {} } @@ -21659,6 +21666,11 @@ public: } int useTimeSlice() + { + return writePendingData(); + } + + int writePendingData() { const int numToDo = getTotalSize() / 4; @@ -24316,8 +24328,6 @@ AudioFormatReaderSource::AudioFormatReaderSource (AudioFormatReader* const reade AudioFormatReaderSource::~AudioFormatReaderSource() { - releaseResources(); - if (deleteReader) delete reader; } @@ -24600,7 +24610,7 @@ AudioTransportSource::~AudioTransportSource() { setSource (nullptr); - releaseResources(); + releaseMasterResources(); } void AudioTransportSource::setSource (PositionableAudioSource* const newSource, @@ -24787,7 +24797,7 @@ void AudioTransportSource::prepareToPlay (int samplesPerBlockExpected, isPrepared = true; } -void AudioTransportSource::releaseResources() +void AudioTransportSource::releaseMasterResources() { const ScopedLock sl (callbackLock); @@ -24797,6 +24807,11 @@ void AudioTransportSource::releaseResources() isPrepared = false; } +void AudioTransportSource::releaseResources() +{ + releaseMasterResources(); +} + void AudioTransportSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { const ScopedLock sl (callbackLock); @@ -26779,6 +26794,8 @@ bool AudioIODevice::showControlPanel() return false; } +void AudioIODeviceCallback::audioDeviceError (const String&) {} + END_JUCE_NAMESPACE /*** End of inlined file: juce_AudioIODevice.cpp ***/ @@ -29506,8 +29523,8 @@ int MidiMessage::getChannel() const noexcept { if ((data[0] & 0xf0) != 0xf0) return (data[0] & 0xf) + 1; - else - return 0; + + return 0; } bool MidiMessage::isForChannel (const int channel) const noexcept @@ -29560,8 +29577,8 @@ uint8 MidiMessage::getVelocity() const noexcept { if (isNoteOnOrOff()) return data[2]; - else - return 0; + + return 0; } float MidiMessage::getFloatVelocity() const noexcept @@ -29588,6 +29605,7 @@ bool MidiMessage::isAftertouch() const noexcept int MidiMessage::getAfterTouchValue() const noexcept { + jassert (isAftertouch()); return data[2]; } @@ -29612,7 +29630,6 @@ bool MidiMessage::isChannelPressure() const noexcept int MidiMessage::getChannelPressureValue() const noexcept { jassert (isChannelPressure()); - return data[1]; } @@ -29632,6 +29649,7 @@ bool MidiMessage::isProgramChange() const noexcept int MidiMessage::getProgramChangeNumber() const noexcept { + jassert (isProgramChange()); return data[1]; } @@ -29650,6 +29668,7 @@ bool MidiMessage::isPitchWheel() const noexcept int MidiMessage::getPitchWheelValue() const noexcept { + jassert (isPitchWheel()); return data[1] | (data[2] << 7); } @@ -29659,7 +29678,8 @@ const MidiMessage MidiMessage::pitchWheel (const int channel, jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16 jassert (isPositiveAndBelow (position, (int) 0x4000)); - return MidiMessage (MidiHelpers::initialByte (0xe0, channel), position & 127, (position >> 7) & 127); + return MidiMessage (MidiHelpers::initialByte (0xe0, channel), + position & 127, (position >> 7) & 127); } bool MidiMessage::isController() const noexcept @@ -29670,14 +29690,12 @@ bool MidiMessage::isController() const noexcept int MidiMessage::getControllerNumber() const noexcept { jassert (isController()); - return data[1]; } int MidiMessage::getControllerValue() const noexcept { jassert (isController()); - return data[2]; } @@ -29686,12 +29704,13 @@ const MidiMessage MidiMessage::controllerEvent (const int channel, const int con // the channel must be between 1 and 16 inclusive jassert (channel > 0 && channel <= 16); - return MidiMessage (MidiHelpers::initialByte (0xb0, channel), controllerType & 127, value & 127); + return MidiMessage (MidiHelpers::initialByte (0xb0, channel), + controllerType & 127, value & 127); } const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept { - return noteOn (channel, noteNumber, (uint8)(velocity * 127.0f)); + return noteOn (channel, noteNumber, (uint8) (velocity * 127.0f)); } const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept @@ -29699,7 +29718,8 @@ const MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, jassert (channel > 0 && channel <= 16); jassert (isPositiveAndBelow (noteNumber, (int) 128)); - return MidiMessage (MidiHelpers::initialByte (0x90, channel), noteNumber & 127, MidiHelpers::validVelocity (velocity)); + return MidiMessage (MidiHelpers::initialByte (0x90, channel), + noteNumber & 127, MidiHelpers::validVelocity (velocity)); } const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept @@ -29707,7 +29727,8 @@ const MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, jassert (channel > 0 && channel <= 16); jassert (isPositiveAndBelow (noteNumber, (int) 128)); - return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, MidiHelpers::validVelocity (velocity)); + return MidiMessage (MidiHelpers::initialByte (0x80, channel), + noteNumber & 127, MidiHelpers::validVelocity (velocity)); } const MidiMessage MidiMessage::allNotesOff (const int channel) noexcept @@ -29739,15 +29760,10 @@ const MidiMessage MidiMessage::masterVolume (const float volume) { const int vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000)); - uint8 buf[8]; - buf[0] = 0xf0; - buf[1] = 0x7f; - buf[2] = 0x7f; - buf[3] = 0x04; - buf[4] = 0x01; - buf[5] = (uint8) (vol & 0x7f); - buf[6] = (uint8) (vol >> 7); - buf[7] = 0xf7; + const uint8 buf[] = { 0xf0, 0x7f, 0x7f, 0x04, 0x01, + (uint8) (vol & 0x7f), + (uint8) (vol >> 7), + 0xf7 }; return MidiMessage (buf, 8); } @@ -29778,15 +29794,8 @@ int MidiMessage::getSysExDataSize() const noexcept return isSysEx() ? size - 2 : 0; } -bool MidiMessage::isMetaEvent() const noexcept -{ - return *data == 0xff; -} - -bool MidiMessage::isActiveSense() const noexcept -{ - return *data == 0xfe; -} +bool MidiMessage::isMetaEvent() const noexcept { return *data == 0xff; } +bool MidiMessage::isActiveSense() const noexcept { return *data == 0xfe; } int MidiMessage::getMetaEventType() const noexcept { @@ -29806,26 +29815,20 @@ int MidiMessage::getMetaEventLength() const noexcept const uint8* MidiMessage::getMetaEventData() const noexcept { + jassert (isMetaEvent()); + int n; const uint8* d = data + 2; readVariableLengthVal (d, n); return d + n; } -bool MidiMessage::isTrackMetaEvent() const noexcept -{ - return getMetaEventType() == 0; -} - -bool MidiMessage::isEndOfTrackMetaEvent() const noexcept -{ - return getMetaEventType() == 47; -} +bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; } +bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; } bool MidiMessage::isTextMetaEvent() const noexcept { const int t = getMetaEventType(); - return t > 0 && t < 16; } @@ -29834,23 +29837,13 @@ const String MidiMessage::getTextFromTextMetaEvent() const return String (reinterpret_cast (getMetaEventData()), getMetaEventLength()); } -bool MidiMessage::isTrackNameEvent() const noexcept -{ - return (data[1] == 3) && (*data == 0xff); -} - -bool MidiMessage::isTempoMetaEvent() const noexcept -{ - return (data[1] == 81) && (*data == 0xff); -} - -bool MidiMessage::isMidiChannelMetaEvent() const noexcept -{ - return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); -} +bool MidiMessage::isTrackNameEvent() const noexcept { return (data[1] == 3) && (*data == 0xff); } +bool MidiMessage::isTempoMetaEvent() const noexcept { return (data[1] == 81) && (*data == 0xff); } +bool MidiMessage::isMidiChannelMetaEvent() const noexcept { return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); } int MidiMessage::getMidiChannelMetaEventChannel() const noexcept { + jassert (isMidiChannelMetaEvent()); return data[3] + 1; } @@ -29896,13 +29889,10 @@ double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const n const MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept { - uint8 d[8]; - d[0] = 0xff; - d[1] = 81; - d[2] = 3; - d[3] = (uint8) (microsecondsPerQuarterNote >> 16); - d[4] = (uint8) ((microsecondsPerQuarterNote >> 8) & 0xff); - d[5] = (uint8) (microsecondsPerQuarterNote & 0xff); + const uint8 d[] = { 0xff, 81, 3, + (uint8) (microsecondsPerQuarterNote >> 16), + (uint8) (microsecondsPerQuarterNote >> 8), + (uint8) microsecondsPerQuarterNote }; return MidiMessage (d, 6, 0.0); } @@ -29929,12 +29919,6 @@ void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator) { - uint8 d[8]; - d[0] = 0xff; - d[1] = 0x58; - d[2] = 0x04; - d[3] = (uint8) numerator; - int n = 1; int powerOfTwo = 0; @@ -29944,20 +29928,15 @@ const MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, cons ++powerOfTwo; } - d[4] = (uint8) powerOfTwo; - d[5] = 0x01; - d[6] = 96; + const uint8 d[] = { 0xff, 0x58, 0x04, (uint8) numerator, + (uint8) powerOfTwo, 1, 96 }; return MidiMessage (d, 7, 0.0); } const MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept { - uint8 d[8]; - d[0] = 0xff; - d[1] = 0x20; - d[2] = 0x01; - d[3] = (uint8) jlimit (0, 0xff, channel - 1); + const uint8 d[] = { 0xff, 0x20, 0x01, (uint8) jlimit (0, 0xff, channel - 1) }; return MidiMessage (d, 4, 0.0); } @@ -29977,15 +29956,8 @@ const MidiMessage MidiMessage::endOfTrack() noexcept return MidiMessage (0xff, 0x2f, 0, 0.0); } -bool MidiMessage::isSongPositionPointer() const noexcept -{ - return *data == 0xf2; -} - -int MidiMessage::getSongPositionPointerMidiBeat() const noexcept -{ - return data[1] | (data[2] << 7); -} +bool MidiMessage::isSongPositionPointer() const noexcept { return *data == 0xf2; } +int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { return data[1] | (data[2] << 7); } const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept { @@ -29994,63 +29966,23 @@ const MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeat (positionInMidiBeats >> 7) & 127); } -bool MidiMessage::isMidiStart() const noexcept -{ - return *data == 0xfa; -} +bool MidiMessage::isMidiStart() const noexcept { return *data == 0xfa; } +const MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); } -const MidiMessage MidiMessage::midiStart() noexcept -{ - return MidiMessage (0xfa); -} +bool MidiMessage::isMidiContinue() const noexcept { return *data == 0xfb; } +const MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); } -bool MidiMessage::isMidiContinue() const noexcept -{ - return *data == 0xfb; -} +bool MidiMessage::isMidiStop() const noexcept { return *data == 0xfc; } +const MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); } -const MidiMessage MidiMessage::midiContinue() noexcept -{ - return MidiMessage (0xfb); -} +bool MidiMessage::isMidiClock() const noexcept { return *data == 0xf8; } +const MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); } -bool MidiMessage::isMidiStop() const noexcept -{ - return *data == 0xfc; -} +bool MidiMessage::isQuarterFrame() const noexcept { return *data == 0xf1; } +int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) data[1]) >> 4; } +int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) data[1]) & 0x0f; } -const MidiMessage MidiMessage::midiStop() noexcept -{ - return MidiMessage (0xfc); -} - -bool MidiMessage::isMidiClock() const noexcept -{ - return *data == 0xf8; -} - -const MidiMessage MidiMessage::midiClock() noexcept -{ - return MidiMessage (0xf8); -} - -bool MidiMessage::isQuarterFrame() const noexcept -{ - return *data == 0xf1; -} - -int MidiMessage::getQuarterFrameSequenceNumber() const noexcept -{ - return ((int) data[1]) >> 4; -} - -int MidiMessage::getQuarterFrameValue() const noexcept -{ - return ((int) data[1]) & 0x0f; -} - -const MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, - const int value) noexcept +const MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept { return MidiMessage (0xf1, (sequenceNumber << 4) | value); } @@ -30064,10 +29996,7 @@ bool MidiMessage::isFullFrame() const noexcept && data[4] == 0x01; } -void MidiMessage::getFullFrameParameters (int& hours, - int& minutes, - int& seconds, - int& frames, +void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames, MidiMessage::SmpteTimecodeType& timecodeType) const noexcept { jassert (isFullFrame()); @@ -30079,23 +30008,16 @@ void MidiMessage::getFullFrameParameters (int& hours, frames = data[8]; } -const MidiMessage MidiMessage::fullFrame (const int hours, - const int minutes, - const int seconds, - const int frames, +const MidiMessage MidiMessage::fullFrame (const int hours, const int minutes, + const int seconds, const int frames, MidiMessage::SmpteTimecodeType timecodeType) { - uint8 d[10]; - d[0] = 0xf0; - d[1] = 0x7f; - d[2] = 0x7f; - d[3] = 0x01; - d[4] = 0x01; - d[5] = (uint8) ((hours & 0x01f) | (timecodeType << 5)); - d[6] = (uint8) minutes; - d[7] = (uint8) seconds; - d[8] = (uint8) frames; - d[9] = 0xf7; + const uint8 d[] = { 0xf0, 0x7f, 0x7f, 0x01, 0x01, + (uint8) ((hours & 0x01f) | (timecodeType << 5)), + (uint8) minutes, + (uint8) seconds, + (uint8) frames, + 0xf7 }; return MidiMessage (d, 10, 0.0); } @@ -30117,21 +30039,12 @@ MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand const MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command) { - uint8 d[6]; - d[0] = 0xf0; - d[1] = 0x7f; - d[2] = 0x00; - d[3] = 0x06; - d[4] = (uint8) command; - d[5] = 0xf7; + const uint8 d[] = { 0xf0, 0x7f, 0, 6, (uint8) command, 0xf7 }; return MidiMessage (d, 6, 0.0); } -bool MidiMessage::isMidiMachineControlGoto (int& hours, - int& minutes, - int& seconds, - int& frames) const noexcept +bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept { if (size >= 12 && data[0] == 0xf0 @@ -30152,24 +30065,14 @@ bool MidiMessage::isMidiMachineControlGoto (int& hours, return false; } -const MidiMessage MidiMessage::midiMachineControlGoto (int hours, - int minutes, - int seconds, - int frames) -{ - uint8 d[12]; - d[0] = 0xf0; - d[1] = 0x7f; - d[2] = 0x00; - d[3] = 0x06; - d[4] = 0x44; - d[5] = 0x06; - d[6] = 0x01; - d[7] = (uint8) hours; - d[8] = (uint8) minutes; - d[9] = (uint8) seconds; - d[10] = (uint8) frames; - d[11] = 0xf7; +const MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames) +{ + const uint8 d[] = { 0xf0, 0x7f, 0, 6, 0x44, 6, 1, + (uint8) hours, + (uint8) minutes, + (uint8) seconds, + (uint8) frames, + 0xf7 }; return MidiMessage (d, 12, 0.0); } @@ -31556,7 +31459,7 @@ PluginListComponent::PluginListComponent (KnownPluginList& listToEdit, setSize (400, 600); list.addChangeListener (this); - changeListenerCallback (nullptr); + updateList(); } PluginListComponent::~PluginListComponent() @@ -31572,6 +31475,11 @@ void PluginListComponent::resized() } void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) +{ + updateList(); +} + +void PluginListComponent::updateList() { listBox.updateContent(); listBox.repaint(); @@ -40090,7 +39998,7 @@ class InternalTimerThread : private Thread, private AsyncUpdater { public: - typedef SpinLock LockType; + typedef CriticalSection LockType; // (mysteriously, using a SpinLock here causes problems on some XP machines..) InternalTimerThread() : Thread ("Juce Timer"), @@ -40192,7 +40100,7 @@ public: /* This is needed as a memory barrier to make sure all processing of current timers is done before the boolean is set. This set should never fail since if it was false in the first place, we wouldn't get a message (so it can't be changed from false to true from under us), and if we - get a message then the value is true and the other thread can only set it to true again and + get a message then the value is true and the other thread can only set it to true again and we will get another callback to set it to false. */ callbackNeeded.set (0); @@ -44108,7 +44016,7 @@ ArrowButton::ArrowButton (const String& name, 0.5f, 0.5f)); setComponentEffect (&shadow); - buttonStateChanged(); + updateShadowAndOffset(); } ArrowButton::~ArrowButton() @@ -44129,6 +44037,11 @@ void ArrowButton::paintButton (Graphics& g, } void ArrowButton::buttonStateChanged() +{ + updateShadowAndOffset(); +} + +void ArrowButton::updateShadowAndOffset() { offset = (isDown()) ? 1 : 0; @@ -47110,7 +47023,7 @@ void CodeEditorComponent::cut() insertTextAtCaret (String::empty); } -void CodeEditorComponent::copy() +bool CodeEditorComponent::copyToClipboard() { newTransaction(); @@ -47118,16 +47031,19 @@ void CodeEditorComponent::copy() if (selection.isNotEmpty()) SystemClipboard::copyTextToClipboard (selection); + + return true; } -void CodeEditorComponent::copyThenCut() +bool CodeEditorComponent::cutToClipboard() { - copy(); + copyToClipboard(); cut(); newTransaction(); + return true; } -void CodeEditorComponent::paste() +bool CodeEditorComponent::pasteFromClipboard() { newTransaction(); const String clip (SystemClipboard::getTextFromClipboard()); @@ -47136,9 +47052,10 @@ void CodeEditorComponent::paste() insertTextAtCaret (clip); newTransaction(); + return true; } -void CodeEditorComponent::cursorLeft (const bool moveInWholeWordSteps, const bool selecting) +bool CodeEditorComponent::moveCaretLeft (const bool moveInWholeWordSteps, const bool selecting) { newTransaction(); @@ -47146,9 +47063,11 @@ void CodeEditorComponent::cursorLeft (const bool moveInWholeWordSteps, const boo moveCaretTo (document.findWordBreakBefore (caretPos), selecting); else moveCaretTo (caretPos.movedBy (-1), selecting); + + return true; } -void CodeEditorComponent::cursorRight (const bool moveInWholeWordSteps, const bool selecting) +bool CodeEditorComponent::moveCaretRight (const bool moveInWholeWordSteps, const bool selecting) { newTransaction(); @@ -47156,6 +47075,8 @@ void CodeEditorComponent::cursorRight (const bool moveInWholeWordSteps, const bo moveCaretTo (document.findWordBreakAfter (caretPos), selecting); else moveCaretTo (caretPos.movedBy (1), selecting); + + return true; } void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting) @@ -47173,7 +47094,7 @@ void CodeEditorComponent::moveLineDelta (const int delta, const bool selecting) columnToTryToMaintain = colToMaintain; } -void CodeEditorComponent::cursorDown (const bool selecting) +bool CodeEditorComponent::moveCaretDown (const bool selecting) { newTransaction(); @@ -47181,9 +47102,11 @@ void CodeEditorComponent::cursorDown (const bool selecting) moveCaretTo (CodeDocument::Position (&document, std::numeric_limits::max(), std::numeric_limits::max()), selecting); else moveLineDelta (1, selecting); + + return true; } -void CodeEditorComponent::cursorUp (const bool selecting) +bool CodeEditorComponent::moveCaretUp (const bool selecting) { newTransaction(); @@ -47191,46 +47114,53 @@ void CodeEditorComponent::cursorUp (const bool selecting) moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting); else moveLineDelta (-1, selecting); + + return true; } -void CodeEditorComponent::pageDown (const bool selecting) +bool CodeEditorComponent::pageDown (const bool selecting) { newTransaction(); - scrollBy (jlimit (0, linesOnScreen, 1 + document.getNumLines() - firstLineOnScreen - linesOnScreen)); moveLineDelta (linesOnScreen, selecting); + return true; } -void CodeEditorComponent::pageUp (const bool selecting) +bool CodeEditorComponent::pageUp (const bool selecting) { newTransaction(); - scrollBy (-linesOnScreen); moveLineDelta (-linesOnScreen, selecting); + return true; } -void CodeEditorComponent::scrollUp() +bool CodeEditorComponent::scrollUp() { newTransaction(); scrollBy (1); if (caretPos.getLineNumber() < firstLineOnScreen) moveLineDelta (1, false); + + return true; } -void CodeEditorComponent::scrollDown() +bool CodeEditorComponent::scrollDown() { newTransaction(); scrollBy (-1); if (caretPos.getLineNumber() >= firstLineOnScreen + linesOnScreen) moveLineDelta (-1, false); + + return true; } -void CodeEditorComponent::goToStartOfDocument (const bool selecting) +bool CodeEditorComponent::moveCaretToTop (const bool selecting) { newTransaction(); moveCaretTo (CodeDocument::Position (&document, 0, 0), selecting); + return true; } namespace CodeEditorHelpers @@ -47253,7 +47183,7 @@ namespace CodeEditorHelpers } } -void CodeEditorComponent::goToStartOfLine (const bool selecting) +bool CodeEditorComponent::moveCaretToStartOfLine (const bool selecting) { newTransaction(); @@ -47263,21 +47193,24 @@ void CodeEditorComponent::goToStartOfLine (const bool selecting) index = 0; moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), index), selecting); + return true; } -void CodeEditorComponent::goToEndOfDocument (const bool selecting) +bool CodeEditorComponent::moveCaretToEnd (const bool selecting) { newTransaction(); moveCaretTo (CodeDocument::Position (&document, std::numeric_limits::max(), std::numeric_limits::max()), selecting); + return true; } -void CodeEditorComponent::goToEndOfLine (const bool selecting) +bool CodeEditorComponent::moveCaretToEndOfLine (const bool selecting) { newTransaction(); moveCaretTo (CodeDocument::Position (&document, caretPos.getLineNumber(), std::numeric_limits::max()), selecting); + return true; } -void CodeEditorComponent::backspace (const bool moveInWholeWordSteps) +bool CodeEditorComponent::deleteBackwards (const bool moveInWholeWordSteps) { if (moveInWholeWordSteps) { @@ -47291,9 +47224,10 @@ void CodeEditorComponent::backspace (const bool moveInWholeWordSteps) } cut(); + return true; } -void CodeEditorComponent::deleteForward (const bool moveInWholeWordSteps) +bool CodeEditorComponent::deleteForwards (const bool moveInWholeWordSteps) { if (moveInWholeWordSteps) { @@ -47309,25 +47243,29 @@ void CodeEditorComponent::deleteForward (const bool moveInWholeWordSteps) } cut(); + return true; } -void CodeEditorComponent::selectAll() +bool CodeEditorComponent::selectAll() { newTransaction(); moveCaretTo (CodeDocument::Position (&document, std::numeric_limits::max(), std::numeric_limits::max()), false); moveCaretTo (CodeDocument::Position (&document, 0, 0), true); + return true; } -void CodeEditorComponent::undo() +bool CodeEditorComponent::undo() { document.undo(); scrollToKeepCaretOnScreen(); + return true; } -void CodeEditorComponent::redo() +bool CodeEditorComponent::redo() { document.redo(); scrollToKeepCaretOnScreen(); + return true; } void CodeEditorComponent::newTransaction() @@ -47360,114 +47298,29 @@ const String CodeEditorComponent::getTextInRange (const Range& range) const bool CodeEditorComponent::keyPressed (const KeyPress& key) { - const bool moveInWholeWordSteps = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); - const bool shiftDown = key.getModifiers().isShiftDown(); - - if (key.isKeyCode (KeyPress::leftKey)) - { - cursorLeft (moveInWholeWordSteps, shiftDown); - } - else if (key.isKeyCode (KeyPress::rightKey)) - { - cursorRight (moveInWholeWordSteps, shiftDown); - } - else if (key.isKeyCode (KeyPress::upKey)) - { - if (key.getModifiers().isCtrlDown() && ! shiftDown) - scrollDown(); -#if JUCE_MAC - else if (key.getModifiers().isCommandDown()) - goToStartOfDocument (shiftDown); -#endif - else - cursorUp (shiftDown); - } - else if (key.isKeyCode (KeyPress::downKey)) - { - if (key.getModifiers().isCtrlDown() && ! shiftDown) - scrollUp(); -#if JUCE_MAC - else if (key.getModifiers().isCommandDown()) - goToEndOfDocument (shiftDown); -#endif - else - cursorDown (shiftDown); - } - else if (key.isKeyCode (KeyPress::pageDownKey)) - { - pageDown (shiftDown); - } - else if (key.isKeyCode (KeyPress::pageUpKey)) - { - pageUp (shiftDown); - } - else if (key.isKeyCode (KeyPress::homeKey)) - { - if (moveInWholeWordSteps) - goToStartOfDocument (shiftDown); - else - goToStartOfLine (shiftDown); - } - else if (key.isKeyCode (KeyPress::endKey)) + if (! TextEditorKeyMapper::invokeKeyFunction (*this, key)) { - if (moveInWholeWordSteps) - goToEndOfDocument (shiftDown); + if (key == KeyPress::tabKey || key.getTextCharacter() == '\t') + { + insertTabAtCaret(); + } + else if (key == KeyPress::returnKey) + { + newTransaction(); + insertTextAtCaret (document.getNewLineCharacters()); + } + else if (key.isKeyCode (KeyPress::escapeKey)) + { + newTransaction(); + } + else if (key.getTextCharacter() >= ' ') + { + insertTextAtCaret (String::charToString (key.getTextCharacter())); + } else - goToEndOfLine (shiftDown); - } - else if (key.isKeyCode (KeyPress::backspaceKey)) - { - backspace (moveInWholeWordSteps); - } - else if (key.isKeyCode (KeyPress::deleteKey)) - { - deleteForward (moveInWholeWordSteps); - } - else if (key == KeyPress ('c', ModifierKeys::commandModifier, 0)) - { - copy(); - } - else if (key == KeyPress ('x', ModifierKeys::commandModifier, 0)) - { - copyThenCut(); - } - else if (key == KeyPress ('v', ModifierKeys::commandModifier, 0)) - { - paste(); - } - else if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) - { - undo(); - } - else if (key == KeyPress ('y', ModifierKeys::commandModifier, 0) - || key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)) - { - redo(); - } - else if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) - { - selectAll(); - } - else if (key == KeyPress::tabKey || key.getTextCharacter() == '\t') - { - insertTabAtCaret(); - } - else if (key == KeyPress::returnKey) - { - newTransaction(); - insertTextAtCaret (document.getNewLineCharacters()); - } - else if (key.isKeyCode (KeyPress::escapeKey)) - { - newTransaction(); - } - else if (key.getTextCharacter() >= ' ') - { - insertTextAtCaret (String::charToString (key.getTextCharacter())); - } - else - { - return false; + { + return false; + } } return true; @@ -48356,7 +48209,7 @@ ComboBox::ComboBox (const String& name) noChoicesMessage (TRANS("(no choices)")) { setRepaintsOnMouseActivity (true); - lookAndFeelChanged(); + ComboBox::lookAndFeelChanged(); currentId.addListener (this); } @@ -49714,8 +49567,8 @@ ListBox::ListBox (const String& name, ListBoxModel* const model_) { addAndMakeVisible (viewport = new ListViewport (*this)); - setWantsKeyboardFocus (true); - colourChanged(); + ListBox::setWantsKeyboardFocus (true); + ListBox::colourChanged(); } ListBox::~ListBox() @@ -50425,8 +50278,7 @@ public: void paintContent (Graphics& g, int w, int h) { g.setFont (font); - g.setColour (Colours::black); - + g.setColour (findColour (TooltipWindow::textColourId, true)); g.drawFittedText (text, 0, 0, w, h, Justification::centred, 1); } @@ -50502,7 +50354,7 @@ Slider::Slider (const String& name) setWantsKeyboardFocus (false); setRepaintsOnMouseActivity (true); - lookAndFeelChanged(); + Slider::lookAndFeelChanged(); updateText(); currentValue.addListener (this); @@ -51391,8 +51243,7 @@ void Slider::mouseDown (const MouseEvent& e) { mouseWasHidden = false; incDecDragged = false; - mouseXWhenLastDragged = e.x; - mouseYWhenLastDragged = e.y; + mousePosWhenLastDragged = e.getPosition(); mouseDragStartX = e.getMouseDownX(); mouseDragStartY = e.getMouseDownY(); @@ -51585,8 +51436,8 @@ void Slider::mouseDrag (const MouseEvent& e) { if (style == Rotary) { - int dx = e.x - sliderRect.getCentreX(); - int dy = e.y - sliderRect.getCentreY(); + const int dx = e.x - sliderRect.getCentreX(); + const int dy = e.y - sliderRect.getCentreY(); if (dx * dx + dy * dy > 25) { @@ -51691,8 +51542,8 @@ void Slider::mouseDrag (const MouseEvent& e) { const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag || (style == IncDecButtons && incDecDragDirectionIsHorizontal())) - ? e.x - mouseXWhenLastDragged - : e.y - mouseYWhenLastDragged; + ? e.x - mousePosWhenLastDragged.getX() + : e.y - mousePosWhenLastDragged.getY(); const double maxSpeed = jmax (200, sliderRegionSize); double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff)); @@ -51751,8 +51602,7 @@ void Slider::mouseDrag (const MouseEvent& e) minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); } - mouseXWhenLastDragged = e.x; - mouseYWhenLastDragged = e.y; + mousePosWhenLastDragged = e.getPosition(); } } @@ -54160,20 +54010,28 @@ void TextEditor::newTransaction() undoManager.beginNewTransaction(); } -void TextEditor::doUndoRedo (const bool isRedo) +bool TextEditor::undoOrRedo (const bool shouldUndo) { if (! isReadOnly()) { - if (isRedo ? undoManager.redo() - : undoManager.undo()) + newTransaction(); + + if (shouldUndo ? undoManager.undo() + : undoManager.redo()) { scrollToMakeSureCursorIsVisible(); repaint(); textChanged(); + return true; } } + + return false; } +bool TextEditor::undo() { return undoOrRedo (true); } +bool TextEditor::redo() { return undoOrRedo (false); } + void TextEditor::setMultiLine (const bool shouldBeMultiLine, const bool shouldWordWrap) { @@ -55001,163 +54859,198 @@ void TextEditor::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, flo Component::mouseWheelMove (e, wheelIncrementX, wheelIncrementY); } -bool TextEditor::keyPressed (const KeyPress& key) +bool TextEditor::moveCaretWithTransation (const int newPos, const bool selecting) { - if (isReadOnly() && key != KeyPress ('c', ModifierKeys::commandModifier, 0)) - return false; + newTransaction(); + moveCaretTo (newPos, selecting); + return true; +} + +bool TextEditor::moveCaretLeft (bool moveInWholeWordSteps, bool selecting) +{ + int pos = getCaretPosition(); + + if (moveInWholeWordSteps) + pos = findWordBreakBefore (pos); + else + --pos; + + return moveCaretWithTransation (pos, selecting); +} + +bool TextEditor::moveCaretRight (bool moveInWholeWordSteps, bool selecting) +{ + int pos = getCaretPosition(); + + if (moveInWholeWordSteps) + pos = findWordBreakAfter (pos); + else + ++pos; + + return moveCaretWithTransation (pos, selecting); +} + +bool TextEditor::moveCaretUp (bool selecting) +{ + if (! isMultiLine()) + return moveCaretToStartOfLine (selecting); - const bool moveInWholeWordSteps = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f), selecting); +} - if (key.isKeyCode (KeyPress::leftKey) - || key.isKeyCode (KeyPress::upKey)) - { - newTransaction(); +bool TextEditor::moveCaretDown (bool selecting) +{ + if (! isMultiLine()) + return moveCaretToEndOfLine (selecting); - int newPos; + const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f), selecting); +} - if (isMultiLine() && key.isKeyCode (KeyPress::upKey)) - newPos = indexAtPosition (caretPos.getX(), caretPos.getY() - 1.0f); - else if (moveInWholeWordSteps) - newPos = findWordBreakBefore (getCaretPosition()); - else - newPos = getCaretPosition() - 1; +bool TextEditor::pageUp (bool selecting) +{ + if (! isMultiLine()) + return moveCaretToStartOfLine (selecting); - moveCaretTo (newPos, key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::rightKey) - || key.isKeyCode (KeyPress::downKey)) - { - newTransaction(); + const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), selecting); +} - int newPos; +bool TextEditor::pageDown (bool selecting) +{ + if (! isMultiLine()) + return moveCaretToEndOfLine (selecting); - if (isMultiLine() && key.isKeyCode (KeyPress::downKey)) - newPos = indexAtPosition (caretPos.getX(), caretPos.getBottom() + 1.0f); - else if (moveInWholeWordSteps) - newPos = findWordBreakAfter (getCaretPosition()); - else - newPos = getCaretPosition() + 1; + const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), selecting); +} - moveCaretTo (newPos, key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::pageDownKey) && isMultiLine()) - { - newTransaction(); +void TextEditor::scrollByLines (int deltaLines) +{ + ScrollBar* scrollbar = viewport->getVerticalScrollBar(); - moveCaretTo (indexAtPosition (caretPos.getX(), caretPos.getBottom() + viewport->getViewHeight()), - key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::pageUpKey) && isMultiLine()) - { - newTransaction(); + if (scrollbar != nullptr) + scrollbar->moveScrollbarInSteps (deltaLines); +} - moveCaretTo (indexAtPosition (caretPos.getX(), caretPos.getY() - viewport->getViewHeight()), - key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::homeKey)) - { - newTransaction(); +bool TextEditor::scrollDown() +{ + scrollByLines (-1); + return true; +} - if (isMultiLine() && ! moveInWholeWordSteps) - moveCaretTo (indexAtPosition (0.0f, caretPos.getY()), - key.getModifiers().isShiftDown()); - else - moveCaretTo (0, key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::endKey)) - { - newTransaction(); +bool TextEditor::scrollUp() +{ + scrollByLines (1); + return true; +} - if (isMultiLine() && ! moveInWholeWordSteps) - moveCaretTo (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), - key.getModifiers().isShiftDown()); - else - moveCaretTo (getTotalNumChars(), key.getModifiers().isShiftDown()); - } - else if (key.isKeyCode (KeyPress::backspaceKey)) +bool TextEditor::moveCaretToTop (bool selecting) +{ + return moveCaretWithTransation (0, selecting); +} + +bool TextEditor::moveCaretToStartOfLine (bool selecting) +{ + const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition (0.0f, caretPos.getY()), selecting); +} + +bool TextEditor::moveCaretToEnd (bool selecting) +{ + return moveCaretWithTransation (getTotalNumChars(), selecting); +} + +bool TextEditor::moveCaretToEndOfLine (bool selecting) +{ + const Rectangle caretPos (getCaretRectangle().toFloat()); + return moveCaretWithTransation (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), selecting); +} + +bool TextEditor::deleteBackwards (bool moveInWholeWordSteps) +{ + if (moveInWholeWordSteps) + moveCaretTo (findWordBreakBefore (getCaretPosition()), true); + else if (selection.isEmpty() && selection.getStart() > 0) + selection.setStart (selection.getEnd() - 1); + + cut(); + return true; +} + +bool TextEditor::deleteForwards (bool /*moveInWholeWordSteps*/) +{ + if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) + selection.setEnd (selection.getStart() + 1); + + cut(); + return true; +} + +bool TextEditor::copyToClipboard() +{ + newTransaction(); + copy(); + return true; +} + +bool TextEditor::cutToClipboard() +{ + newTransaction(); + copy(); + cut(); + return true; +} + +bool TextEditor::pasteFromClipboard() +{ + newTransaction(); + paste(); + return true; +} + +bool TextEditor::selectAll() +{ + newTransaction(); + moveCaretTo (getTotalNumChars(), false); + moveCaretTo (0, true); + return true; +} + +bool TextEditor::keyPressed (const KeyPress& key) +{ + if (isReadOnly() && key != KeyPress ('c', ModifierKeys::commandModifier, 0)) + return false; + + if (! TextEditorKeyMapper::invokeKeyFunction (*this, key)) { - if (moveInWholeWordSteps) + if (key == KeyPress::returnKey) { - moveCaretTo (findWordBreakBefore (getCaretPosition()), true); + newTransaction(); + + if (returnKeyStartsNewLine) + insertTextAtCaret ("\n"); + else + returnPressed(); } - else + else if (key.isKeyCode (KeyPress::escapeKey)) { - if (selection.isEmpty() && selection.getStart() > 0) - selection.setStart (selection.getEnd() - 1); + newTransaction(); + moveCaretTo (getCaretPosition(), false); + escapePressed(); } + else if (key.getTextCharacter() >= ' ' + || (tabKeyUsed && (key.getTextCharacter() == '\t'))) + { + insertTextAtCaret (String::charToString (key.getTextCharacter())); - cut(); - } - else if (key.isKeyCode (KeyPress::deleteKey)) - { - if (key.getModifiers().isShiftDown()) - copy(); - - if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) - selection.setEnd (selection.getStart() + 1); - - cut(); - } - else if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) - || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) - { - newTransaction(); - copy(); - } - else if (key == KeyPress ('x', ModifierKeys::commandModifier, 0)) - { - newTransaction(); - copy(); - cut(); - } - else if (key == KeyPress ('v', ModifierKeys::commandModifier, 0) - || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) - { - newTransaction(); - paste(); - } - else if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) - { - newTransaction(); - doUndoRedo (false); - } - else if (key == KeyPress ('y', ModifierKeys::commandModifier, 0)) - { - newTransaction(); - doUndoRedo (true); - } - else if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) - { - newTransaction(); - moveCaretTo (getTotalNumChars(), false); - moveCaretTo (0, true); - } - else if (key == KeyPress::returnKey) - { - newTransaction(); - - if (returnKeyStartsNewLine) - insertTextAtCaret ("\n"); + lastTransactionTime = Time::getApproximateMillisecondCounter(); + } else - returnPressed(); - } - else if (key.isKeyCode (KeyPress::escapeKey)) - { - newTransaction(); - moveCaretTo (getCaretPosition(), false); - escapePressed(); - } - else if (key.getTextCharacter() >= ' ' - || (tabKeyUsed && (key.getTextCharacter() == '\t'))) - { - insertTextAtCaret (String::charToString (key.getTextCharacter())); - - lastTransactionTime = Time::getApproximateMillisecondCounter(); - } - else - { - return false; + { + return false; + } } return true; @@ -55168,10 +55061,10 @@ bool TextEditor::keyStateChanged (const bool isKeyDown) if (! isKeyDown) return false; -#if JUCE_WINDOWS + #if JUCE_WINDOWS if (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0).isCurrentlyDown()) return false; // We need to explicitly allow alt-F4 to pass through on Windows -#endif + #endif // (overridden to avoid forwarding key events to the parent) return ! ModifierKeys::getCurrentModifiers().isCommandDown(); @@ -55206,38 +55099,14 @@ void TextEditor::performPopupMenuAction (const int menuItemID) { switch (menuItemID) { - case baseMenuItemID + 1: - copy(); - cut(); - break; - - case baseMenuItemID + 2: - copy(); - break; - - case baseMenuItemID + 3: - paste(); - break; - - case baseMenuItemID + 4: - cut(); - break; - - case baseMenuItemID + 5: - moveCaretTo (getTotalNumChars(), false); - moveCaretTo (0, true); - break; - - case baseMenuItemID + 6: - doUndoRedo (false); - break; - - case baseMenuItemID + 7: - doUndoRedo (true); - break; - - default: - break; + case baseMenuItemID + 1: cutToClipboard(); break; + case baseMenuItemID + 2: copyToClipboard(); break; + case baseMenuItemID + 3: pasteFromClipboard(); break; + case baseMenuItemID + 4: cut(); break; + case baseMenuItemID + 5: selectAll(); break; + case baseMenuItemID + 6: undo(); break; + case baseMenuItemID + 7: redo(); break; + default: break; } } @@ -58984,19 +58853,7 @@ FileBrowserComponent::FileBrowserComponent (int flags_, addAndMakeVisible (¤tPathBox); currentPathBox.setEditableText (true); - - StringArray rootNames, rootPaths; - getRoots (rootNames, rootPaths); - - for (int i = 0; i < rootNames.size(); ++i) - { - if (rootNames[i].isEmpty()) - currentPathBox.addSeparator(); - else - currentPathBox.addItem (rootNames[i], i + 1); - } - - currentPathBox.addSeparator(); + resetRecentPaths(); currentPathBox.addListener (this); addAndMakeVisible (&filenameBox); @@ -59150,6 +59007,24 @@ void FileBrowserComponent::setRoot (const File& newRootDirectory) && currentRoot.getParentDirectory() != currentRoot); } +void FileBrowserComponent::resetRecentPaths() +{ + currentPathBox.clear(); + + StringArray rootNames, rootPaths; + getRoots (rootNames, rootPaths); + + for (int i = 0; i < rootNames.size(); ++i) + { + if (rootNames[i].isEmpty()) + currentPathBox.addSeparator(); + else + currentPathBox.addItem (rootNames[i], i + 1); + } + + currentPathBox.addSeparator(); +} + void FileBrowserComponent::goUp() { setRoot (getRoot().getParentDirectory()); @@ -59350,7 +59225,7 @@ void FileBrowserComponent::comboBoxChanged (ComboBox*) void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths) { -#if JUCE_WINDOWS + #if JUCE_WINDOWS Array roots; File::findFileSystemRoots (roots); rootPaths.clear(); @@ -59386,9 +59261,8 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa rootNames.add ("Documents"); rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); rootNames.add ("Desktop"); -#endif -#if JUCE_MAC + #elif JUCE_MAC rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); rootNames.add ("Home folder"); rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName()); @@ -59413,16 +59287,15 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa rootNames.add (volume.getFileName()); } } -#endif -#if JUCE_LINUX + #else rootPaths.add ("/"); rootNames.add ("/"); rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName()); rootNames.add ("Home folder"); rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName()); rootNames.add ("Desktop"); -#endif + #endif } END_JUCE_NAMESPACE @@ -59666,7 +59539,7 @@ FileChooserDialogBox::FileChooserDialogBox (const String& name, content->newFolderButton.addListener (this); content->chooserComponent.addListener (this); - selectionChanged(); + FileChooserDialogBox::selectionChanged(); } FileChooserDialogBox::~FileChooserDialogBox() @@ -61647,29 +61520,64 @@ namespace KeyPressHelpers { "rewind", KeyPress::rewindKey } }; - const String numberPadPrefix() { return "numpad "; } + struct ModifierDescription + { + const char* name; + int flag; + }; + + static const ModifierDescription modifierNames[] = + { + { "ctrl", ModifierKeys::ctrlModifier }, + { "control", ModifierKeys::ctrlModifier }, + { "ctl", ModifierKeys::ctrlModifier }, + { "shift", ModifierKeys::shiftModifier }, + { "shft", ModifierKeys::shiftModifier }, + { "alt", ModifierKeys::altModifier }, + { "option", ModifierKeys::altModifier }, + { "command", ModifierKeys::commandModifier }, + { "cmd", ModifierKeys::commandModifier } + }; + + const char* numberPadPrefix() noexcept { return "numpad "; } + + int getNumpadKeyCode (const String& desc) + { + if (desc.containsIgnoreCase (numberPadPrefix())) + { + const juce_wchar lastChar = desc.trimEnd().getLastCharacter(); + + switch (lastChar) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return KeyPress::numberPad0 + lastChar - '0'; + + case '+': return KeyPress::numberPadAdd; + case '-': return KeyPress::numberPadSubtract; + case '*': return KeyPress::numberPadMultiply; + case '/': return KeyPress::numberPadDivide; + case '.': return KeyPress::numberPadDecimalPoint; + case '=': return KeyPress::numberPadEquals; + + default: break; + } + + if (desc.endsWith ("separator")) return KeyPress::numberPadSeparator; + if (desc.endsWith ("delete")) return KeyPress::numberPadDelete; + } + + return 0; + } } const KeyPress KeyPress::createFromDescription (const String& desc) { int modifiers = 0; - if (desc.containsWholeWordIgnoreCase ("ctrl") - || desc.containsWholeWordIgnoreCase ("control") - || desc.containsWholeWordIgnoreCase ("ctl")) - modifiers |= ModifierKeys::ctrlModifier; - - if (desc.containsWholeWordIgnoreCase ("shift") - || desc.containsWholeWordIgnoreCase ("shft")) - modifiers |= ModifierKeys::shiftModifier; - - if (desc.containsWholeWordIgnoreCase ("alt") - || desc.containsWholeWordIgnoreCase ("option")) - modifiers |= ModifierKeys::altModifier; - - if (desc.containsWholeWordIgnoreCase ("command") - || desc.containsWholeWordIgnoreCase ("cmd")) - modifiers |= ModifierKeys::commandModifier; + for (int i = 0; i < numElementsInArray (KeyPressHelpers::modifierNames); ++i) + if (desc.containsWholeWordIgnoreCase (KeyPressHelpers::modifierNames[i].name)) + modifiers |= KeyPressHelpers::modifierNames[i].flag; int key = 0; @@ -61683,44 +61591,28 @@ const KeyPress KeyPress::createFromDescription (const String& desc) } if (key == 0) - { - // see if it's a numpad key.. - if (desc.containsIgnoreCase (KeyPressHelpers::numberPadPrefix())) - { - const juce_wchar lastChar = desc.trimEnd().getLastCharacter(); + key = KeyPressHelpers::getNumpadKeyCode (desc); - if (lastChar >= '0' && lastChar <= '9') key = numberPad0 + lastChar - '0'; - else if (lastChar == '+') key = numberPadAdd; - else if (lastChar == '-') key = numberPadSubtract; - else if (lastChar == '*') key = numberPadMultiply; - else if (lastChar == '/') key = numberPadDivide; - else if (lastChar == '.') key = numberPadDecimalPoint; - else if (lastChar == '=') key = numberPadEquals; - else if (desc.endsWith ("separator")) key = numberPadSeparator; - else if (desc.endsWith ("delete")) key = numberPadDelete; - } + if (key == 0) + { + // see if it's a function key.. + if (! desc.containsChar ('#')) // avoid mistaking hex-codes like "#f1" + for (int i = 1; i <= 12; ++i) + if (desc.containsWholeWordIgnoreCase ("f" + String (i))) + key = F1Key + i - 1; if (key == 0) { - // see if it's a function key.. - if (! desc.containsChar ('#')) // avoid mistaking hex-codes like "#f1" - for (int i = 1; i <= 12; ++i) - if (desc.containsWholeWordIgnoreCase ("f" + String (i))) - key = F1Key + i - 1; - - if (key == 0) - { - // give up and use the hex code.. - const int hexCode = desc.fromFirstOccurrenceOf ("#", false, false) - .toLowerCase() - .retainCharacters ("0123456789abcdef") - .getHexValue32(); + // give up and use the hex code.. + const int hexCode = desc.fromFirstOccurrenceOf ("#", false, false) + .toLowerCase() + .retainCharacters ("0123456789abcdef") + .getHexValue32(); - if (hexCode > 0) - key = hexCode; - else - key = CharacterFunctions::toUpperCase (desc.getLastCharacter()); - } + if (hexCode > 0) + key = hexCode; + else + key = CharacterFunctions::toUpperCase (desc.getLastCharacter()); } } @@ -74108,10 +74000,6 @@ public: setOutlineThickness (1); } - ~MidiInputSelectorComponentListBox() - { - } - int getNumRows() { return items.size(); @@ -74229,7 +74117,7 @@ public: type->scanForDevices(); setup.manager->addChangeListener (this); - changeListenerCallback (nullptr); + updateAllControls(); } ~AudioDeviceSettingsPanel() @@ -74404,71 +74292,15 @@ public: } } - void updateControlPanelButton() + void updateAllControls() { - AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); - - showUIButton = nullptr; + updateOutputsComboBox(); + updateInputsComboBox(); - if (currentDevice != nullptr && currentDevice->hasControlPanel()) - { - addAndMakeVisible (showUIButton = new TextButton (TRANS ("show this device's control panel"), - TRANS ("opens the device's own control panel"))); - showUIButton->addListener (this); - } - - resized(); - } + updateControlPanelButton(); - void changeListenerCallback (ChangeBroadcaster*) - { AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); - if (setup.maxNumOutputChannels > 0 || ! type->hasSeparateInputsAndOutputs()) - { - if (outputDeviceDropDown == nullptr) - { - outputDeviceDropDown = new ComboBox (String::empty); - outputDeviceDropDown->addListener (this); - addAndMakeVisible (outputDeviceDropDown); - - outputDeviceLabel = new Label (String::empty, - type->hasSeparateInputsAndOutputs() ? TRANS ("output:") - : TRANS ("device:")); - outputDeviceLabel->attachToComponent (outputDeviceDropDown, true); - - if (setup.maxNumOutputChannels > 0) - { - addAndMakeVisible (testButton = new TextButton (TRANS ("Test"))); - testButton->addListener (this); - } - } - - addNamesToDeviceBox (*outputDeviceDropDown, false); - } - - if (setup.maxNumInputChannels > 0 && type->hasSeparateInputsAndOutputs()) - { - if (inputDeviceDropDown == nullptr) - { - inputDeviceDropDown = new ComboBox (String::empty); - inputDeviceDropDown->addListener (this); - addAndMakeVisible (inputDeviceDropDown); - - inputDeviceLabel = new Label (String::empty, TRANS ("input:")); - inputDeviceLabel->attachToComponent (inputDeviceDropDown, true); - - addAndMakeVisible (inputLevelMeter - = new SimpleDeviceManagerInputLevelMeter (setup.manager)); - } - - addNamesToDeviceBox (*inputDeviceDropDown, true); - } - - updateControlPanelButton(); - showCorrectDeviceName (inputDeviceDropDown, true); - showCorrectDeviceName (outputDeviceDropDown, false); - if (currentDevice != nullptr) { if (setup.maxNumOutputChannels > 0 @@ -74511,66 +74343,8 @@ public: inputChanList = nullptr; } - // sample rate.. - { - if (sampleRateDropDown == nullptr) - { - addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty)); - - sampleRateLabel = new Label (String::empty, TRANS ("sample rate:")); - sampleRateLabel->attachToComponent (sampleRateDropDown, true); - } - else - { - sampleRateDropDown->clear(); - sampleRateDropDown->removeListener (this); - } - - const int numRates = currentDevice->getNumSampleRates(); - - for (int i = 0; i < numRates; ++i) - { - const int rate = roundToInt (currentDevice->getSampleRate (i)); - sampleRateDropDown->addItem (String (rate) + " Hz", rate); - } - - sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), true); - sampleRateDropDown->addListener (this); - } - - // buffer size - { - if (bufferSizeDropDown == nullptr) - { - addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty)); - - bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:")); - bufferSizeLabel->attachToComponent (bufferSizeDropDown, true); - } - else - { - bufferSizeDropDown->clear(); - bufferSizeDropDown->removeListener (this); - } - - const int numBufferSizes = currentDevice->getNumBufferSizesAvailable(); - double currentRate = currentDevice->getCurrentSampleRate(); - if (currentRate == 0) - currentRate = 48000.0; - - for (int i = 0; i < numBufferSizes; ++i) - { - const int bs = currentDevice->getBufferSizeSamples (i); - bufferSizeDropDown->addItem (String (bs) - + " samples (" - + String (bs * 1000.0 / currentRate, 1) - + " ms)", - bs); - } - - bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true); - bufferSizeDropDown->addListener (this); - } + updateSampleRateComboBox (currentDevice); + updateBufferSizeComboBox (currentDevice); } else { @@ -74592,6 +74366,11 @@ public: setSize (getWidth(), getLowestY() + 4); } + void changeListenerCallback (ChangeBroadcaster*) + { + updateAllControls(); + } + private: AudioIODeviceType* const type; const AudioIODeviceType::DeviceSetupDetails setup; @@ -74640,6 +74419,133 @@ private: return y; } + void updateControlPanelButton() + { + AudioIODevice* const currentDevice = setup.manager->getCurrentAudioDevice(); + showUIButton = nullptr; + + if (currentDevice != nullptr && currentDevice->hasControlPanel()) + { + addAndMakeVisible (showUIButton = new TextButton (TRANS ("show this device's control panel"), + TRANS ("opens the device's own control panel"))); + showUIButton->addListener (this); + } + + resized(); + } + + void updateOutputsComboBox() + { + if (setup.maxNumOutputChannels > 0 || ! type->hasSeparateInputsAndOutputs()) + { + if (outputDeviceDropDown == nullptr) + { + outputDeviceDropDown = new ComboBox (String::empty); + outputDeviceDropDown->addListener (this); + addAndMakeVisible (outputDeviceDropDown); + + outputDeviceLabel = new Label (String::empty, + type->hasSeparateInputsAndOutputs() ? TRANS ("output:") + : TRANS ("device:")); + outputDeviceLabel->attachToComponent (outputDeviceDropDown, true); + + if (setup.maxNumOutputChannels > 0) + { + addAndMakeVisible (testButton = new TextButton (TRANS ("Test"))); + testButton->addListener (this); + } + } + + addNamesToDeviceBox (*outputDeviceDropDown, false); + } + + showCorrectDeviceName (outputDeviceDropDown, false); + } + + void updateInputsComboBox() + { + if (setup.maxNumInputChannels > 0 && type->hasSeparateInputsAndOutputs()) + { + if (inputDeviceDropDown == nullptr) + { + inputDeviceDropDown = new ComboBox (String::empty); + inputDeviceDropDown->addListener (this); + addAndMakeVisible (inputDeviceDropDown); + + inputDeviceLabel = new Label (String::empty, TRANS ("input:")); + inputDeviceLabel->attachToComponent (inputDeviceDropDown, true); + + addAndMakeVisible (inputLevelMeter + = new SimpleDeviceManagerInputLevelMeter (setup.manager)); + } + + addNamesToDeviceBox (*inputDeviceDropDown, true); + } + + showCorrectDeviceName (inputDeviceDropDown, true); + } + + void updateSampleRateComboBox (AudioIODevice* currentDevice) + { + if (sampleRateDropDown == nullptr) + { + addAndMakeVisible (sampleRateDropDown = new ComboBox (String::empty)); + + sampleRateLabel = new Label (String::empty, TRANS ("sample rate:")); + sampleRateLabel->attachToComponent (sampleRateDropDown, true); + } + else + { + sampleRateDropDown->clear(); + sampleRateDropDown->removeListener (this); + } + + const int numRates = currentDevice->getNumSampleRates(); + + for (int i = 0; i < numRates; ++i) + { + const int rate = roundToInt (currentDevice->getSampleRate (i)); + sampleRateDropDown->addItem (String (rate) + " Hz", rate); + } + + sampleRateDropDown->setSelectedId (roundToInt (currentDevice->getCurrentSampleRate()), true); + sampleRateDropDown->addListener (this); + } + + void updateBufferSizeComboBox (AudioIODevice* currentDevice) + { + if (bufferSizeDropDown == nullptr) + { + addAndMakeVisible (bufferSizeDropDown = new ComboBox (String::empty)); + + bufferSizeLabel = new Label (String::empty, TRANS ("audio buffer size:")); + bufferSizeLabel->attachToComponent (bufferSizeDropDown, true); + } + else + { + bufferSizeDropDown->clear(); + bufferSizeDropDown->removeListener (this); + } + + const int numBufferSizes = currentDevice->getNumBufferSizesAvailable(); + double currentRate = currentDevice->getCurrentSampleRate(); + if (currentRate == 0) + currentRate = 48000.0; + + for (int i = 0; i < numBufferSizes; ++i) + { + const int bs = currentDevice->getBufferSizeSamples (i); + bufferSizeDropDown->addItem (String (bs) + + " samples (" + + String (bs * 1000.0 / currentRate, 1) + + " ms)", + bs); + } + + bufferSizeDropDown->setSelectedId (currentDevice->getCurrentBufferSizeSamples(), true); + bufferSizeDropDown->addListener (this); + } + public: class ChannelSelectorListBox : public ListBox, @@ -74665,10 +74571,6 @@ public: setOutlineThickness (1); } - ~ChannelSelectorListBox() - { - } - void refresh() { items.clear(); @@ -74717,10 +74619,7 @@ public: return items.size(); } - void paintListBoxItem (int row, - Graphics& g, - int width, int height, - bool rowIsSelected) + void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) { if (isPositiveAndBelow (row, items.size())) { @@ -74972,7 +74871,7 @@ AudioDeviceSelectorComponent::AudioDeviceSelectorComponent (AudioDeviceManager& } deviceManager_.addChangeListener (this); - changeListenerCallback (nullptr); + updateAllControls(); } AudioDeviceSelectorComponent::~AudioDeviceSelectorComponent() @@ -75043,7 +74942,7 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha deviceManager.setCurrentAudioDeviceType (type->getTypeName(), true); - changeListenerCallback (nullptr); // needed in case the type hasn't actally changed + updateAllControls(); // needed in case the type hasn't actally changed } } else if (comboBoxThatHasChanged == midiOutputSelector) @@ -75053,11 +74952,14 @@ void AudioDeviceSelectorComponent::comboBoxChanged (ComboBox* comboBoxThatHasCha } void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*) +{ + updateAllControls(); +} + +void AudioDeviceSelectorComponent::updateAllControls() { if (deviceTypeDropDown != nullptr) - { deviceTypeDropDown->setText (deviceManager.getCurrentAudioDeviceType(), false); - } if (audioDeviceSettingsComp == nullptr || audioDeviceSettingsCompType != deviceManager.getCurrentAudioDeviceType()) @@ -77690,7 +77592,7 @@ AlertWindow::AlertWindow (const String& title, if (! JUCEApplication::isStandaloneApp()) setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level - lookAndFeelChanged(); + AlertWindow::lookAndFeelChanged(); constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); } @@ -79256,7 +79158,7 @@ DocumentWindow::DocumentWindow (const String& title, { setResizeLimits (128, 128, 32768, 32768); - lookAndFeelChanged(); + DocumentWindow::lookAndFeelChanged(); } DocumentWindow::~DocumentWindow() @@ -79589,18 +79491,12 @@ ResizableWindow::ResizableWindow (const String& name, ownsContentComponent (false), resizeToFitContent (false), fullscreen (false), - lastNonFullScreenPos (50, 50, 256, 256), constrainer (nullptr) #if JUCE_DEBUG , hasBeenResized (false) #endif { - defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); - - lastNonFullScreenPos.setBounds (50, 50, 256, 256); - - if (addToDesktop_) - Component::addToDesktop (getDesktopWindowStyleFlags()); + initialise (addToDesktop_); } ResizableWindow::ResizableWindow (const String& name, @@ -79610,7 +79506,6 @@ ResizableWindow::ResizableWindow (const String& name, ownsContentComponent (false), resizeToFitContent (false), fullscreen (false), - lastNonFullScreenPos (50, 50, 256, 256), constrainer (nullptr) #if JUCE_DEBUG , hasBeenResized (false) @@ -79618,10 +79513,7 @@ ResizableWindow::ResizableWindow (const String& name, { setBackgroundColour (backgroundColour_); - defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); - - if (addToDesktop_) - Component::addToDesktop (getDesktopWindowStyleFlags()); + initialise (addToDesktop_); } ResizableWindow::~ResizableWindow() @@ -79641,6 +79533,16 @@ ResizableWindow::~ResizableWindow() jassert (getNumChildComponents() == 0); } +void ResizableWindow::initialise (const bool addToDesktop) +{ + defaultConstrainer.setMinimumOnscreenAmounts (0x10000, 16, 24, 16); + + lastNonFullScreenPos.setBounds (50, 50, 256, 256); + + if (addToDesktop) + Component::addToDesktop (ResizableWindow::getDesktopWindowStyleFlags()); +} + int ResizableWindow::getDesktopWindowStyleFlags() const { int styleFlags = TopLevelWindow::getDesktopWindowStyleFlags(); @@ -80612,7 +80514,7 @@ TopLevelWindow::TopLevelWindow (const String& name, setOpaque (true); if (addToDesktop_) - Component::addToDesktop (getDesktopWindowStyleFlags()); + Component::addToDesktop (TopLevelWindow::getDesktopWindowStyleFlags()); else setDropShadowEnabled (true); @@ -97793,22 +97695,17 @@ class GIFLoader public: GIFLoader (InputStream& in) : input (in), - dataBlockIsZero (false), - fresh (false), - finished (false) + dataBlockIsZero (false), fresh (false), finished (false), + currentBit (0), lastBit (0), lastByteIndex (0), + codeSize (0), setCodeSize (0), + maxCode (0), maxCodeSize (0), + firstcode (0), oldcode (0), clearCode (0), endCode (0) { - currentBit = lastBit = lastByteIndex = 0; - maxCode = maxCodeSize = codeSize = setCodeSize = 0; - firstcode = oldcode = 0; - clearCode = end_code = 0; - int imageWidth, imageHeight; int transparent = -1; - if (! getSizeFromHeader (imageWidth, imageHeight)) - return; - - if ((imageWidth <= 0) || (imageHeight <= 0)) + if (! (getSizeFromHeader (imageWidth, imageHeight) + && imageWidth > 0 && imageHeight > 0)) return; unsigned char buf [16]; @@ -97862,8 +97759,6 @@ public: } } - ~GIFLoader() {} - Image image; private: @@ -97875,11 +97770,11 @@ private: int codeSize, setCodeSize; int maxCode, maxCodeSize; int firstcode, oldcode; - int clearCode, end_code; + int clearCode, endCode; enum { maxGifCode = 1 << 12 }; int table [2] [maxGifCode]; int stack [2 * maxGifCode]; - int *sp; + int* sp; bool getSizeFromHeader (int& w, int& h) { @@ -97958,40 +97853,41 @@ private: return n; } - int readLZWByte (const bool initialise, const int inputCodeSize) + void clearTable() { - int code, incode, i; - - if (initialise) + int i; + for (i = 0; i < clearCode; ++i) { - setCodeSize = inputCodeSize; - codeSize = setCodeSize + 1; - clearCode = 1 << setCodeSize; - end_code = clearCode + 1; - maxCodeSize = 2 * clearCode; - maxCode = clearCode + 2; - - getCode (0, true); + table[0][i] = 0; + table[1][i] = i; + } - fresh = true; + for (; i < maxGifCode; ++i) + { + table[0][i] = 0; + table[1][i] = 0; + } + } - for (i = 0; i < clearCode; ++i) - { - table[0][i] = 0; - table[1][i] = i; - } + void initialise (const int inputCodeSize) + { + setCodeSize = inputCodeSize; + codeSize = setCodeSize + 1; + clearCode = 1 << setCodeSize; + endCode = clearCode + 1; + maxCodeSize = 2 * clearCode; + maxCode = clearCode + 2; - for (; i < maxGifCode; ++i) - { - table[0][i] = 0; - table[1][i] = 0; - } + getCode (0, true); - sp = stack; + fresh = true; + clearTable(); + sp = stack; + } - return 0; - } - else if (fresh) + int readLZWByte() + { + if (fresh) { fresh = false; @@ -98008,31 +97904,21 @@ private: if (sp > stack) return *--sp; + int code; + while ((code = getCode (codeSize, false)) >= 0) { if (code == clearCode) { - for (i = 0; i < clearCode; ++i) - { - table[0][i] = 0; - table[1][i] = i; - } - - for (; i < maxGifCode; ++i) - { - table[0][i] = 0; - table[1][i] = 0; - } - + clearTable(); codeSize = setCodeSize + 1; maxCodeSize = 2 * clearCode; maxCode = clearCode + 2; sp = stack; firstcode = oldcode = getCode (codeSize, false); return firstcode; - } - else if (code == end_code) + else if (code == endCode) { if (dataBlockIsZero) return -2; @@ -98047,7 +97933,7 @@ private: return -2; } - incode = code; + const int incode = code; if (code >= maxCode) { @@ -98133,11 +98019,13 @@ private: bool readImage (const int interlace, const int transparent) { - unsigned char c; + { + unsigned char c; + if (input.read (&c, 1) != 1) + return false; - if (input.read (&c, 1) != 1 - || readLZWByte (true, c) < 0) - return false; + initialise (c); + } if (transparent >= 0) { @@ -98154,7 +98042,7 @@ private: uint8* p = destData.data; const bool hasAlpha = image.hasAlphaChannel(); - while ((index = readLZWByte (false, c)) >= 0) + while ((index = readLZWByte()) >= 0) { const uint8* const paletteEntry = palette [index]; @@ -100049,10 +99937,10 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest GZIPCompressorOutputStream::~GZIPCompressorOutputStream() { - flush(); + flushInternal(); } -void GZIPCompressorOutputStream::flush() +void GZIPCompressorOutputStream::flushInternal() { if (! helper->finished) { @@ -100065,6 +99953,11 @@ void GZIPCompressorOutputStream::flush() destStream->flush(); } +void GZIPCompressorOutputStream::flush() +{ + flushInternal(); +} + bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) { if (! helper->finished) @@ -193710,11 +193603,6 @@ static const char* const oggExtensions[] = { ".ogg", 0 }; class OggReader : public AudioFormatReader { - OggVorbisNamespace::OggVorbis_File ovFile; - OggVorbisNamespace::ov_callbacks callbacks; - AudioSampleBuffer reservoir; - int reservoirStart, samplesInReservoir; - public: OggReader (InputStream* const inp) @@ -193860,31 +193748,27 @@ public: } private: + OggVorbisNamespace::OggVorbis_File ovFile; + OggVorbisNamespace::ov_callbacks callbacks; + AudioSampleBuffer reservoir; + int reservoirStart, samplesInReservoir; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggReader); }; class OggWriter : public AudioFormatWriter { - OggVorbisNamespace::ogg_stream_state os; - OggVorbisNamespace::ogg_page og; - OggVorbisNamespace::ogg_packet op; - OggVorbisNamespace::vorbis_info vi; - OggVorbisNamespace::vorbis_comment vc; - OggVorbisNamespace::vorbis_dsp_state vd; - OggVorbisNamespace::vorbis_block vb; - public: - bool ok; OggWriter (OutputStream* const out, const double sampleRate, const int numChannels, const int bitsPerSample, const int qualityIndex) - : AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample) + : AudioFormatWriter (out, TRANS (oggFormatName), sampleRate, numChannels, bitsPerSample), + ok (false) { using namespace OggVorbisNamespace; - ok = false; vorbis_info_init (&vi); @@ -193930,7 +193814,7 @@ public: if (ok) { // write a zero-length packet to show ogg that we're finished.. - write (0, 0); + writeSamples (0); ogg_stream_clear (&os); vorbis_block_clear (&vb); @@ -193950,28 +193834,38 @@ public: bool write (const int** samplesToWrite, int numSamples) { - using namespace OggVorbisNamespace; - if (! ok) - return false; - - if (numSamples > 0) + if (ok) { - const double gain = 1.0 / 0x80000000u; - float** const vorbisBuffer = vorbis_analysis_buffer (&vd, numSamples); + using namespace OggVorbisNamespace; - for (int i = numChannels; --i >= 0;) + if (numSamples > 0) { - float* const dst = vorbisBuffer[i]; - const int* const src = samplesToWrite [i]; + const double gain = 1.0 / 0x80000000u; + float** const vorbisBuffer = vorbis_analysis_buffer (&vd, numSamples); - if (src != nullptr && dst != nullptr) + for (int i = numChannels; --i >= 0;) { - for (int j = 0; j < numSamples; ++j) - dst[j] = (float) (src[j] * gain); + float* const dst = vorbisBuffer[i]; + const int* const src = samplesToWrite [i]; + + if (src != nullptr && dst != nullptr) + { + for (int j = 0; j < numSamples; ++j) + dst[j] = (float) (src[j] * gain); + } } } + + writeSamples (numSamples); } + return ok; + } + + void writeSamples (int numSamples) + { + using namespace OggVorbisNamespace; + vorbis_analysis_wrote (&vd, numSamples); while (vorbis_analysis_blockout (&vd, &vb) == 1) @@ -193996,11 +193890,19 @@ public: } } } - - return true; } + bool ok; + private: + OggVorbisNamespace::ogg_stream_state os; + OggVorbisNamespace::ogg_page og; + OggVorbisNamespace::ogg_packet op; + OggVorbisNamespace::vorbis_info vi; + OggVorbisNamespace::vorbis_comment vc; + OggVorbisNamespace::vorbis_dsp_state vd; + OggVorbisNamespace::vorbis_block vb; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggWriter); }; @@ -284183,31 +284085,10 @@ bool WebBrowserComponent::pageAboutToLoad (const String& url) // compiled on its own). #if JUCE_INCLUDED_FILE -#ifndef JUCE_COREAUDIO_ERROR_LOGGING_ENABLED - #define JUCE_COREAUDIO_ERROR_LOGGING_ENABLED 1 -#endif - -#undef log -#if JUCE_COREAUDIO_LOGGING_ENABLED - #define log(a) Logger::writeToLog (a) +#if JUCE_COREAUDIO_LOGGING_ENABLED //|| ! defined (JUCE_COREAUDIO_LOGGING_ENABLED) + #define JUCE_COREAUDIOLOG(a) Logger::writeToLog (a) #else - #define log(a) -#endif - -#undef OK -#if JUCE_COREAUDIO_ERROR_LOGGING_ENABLED - static bool logAnyErrors_CoreAudio (const OSStatus err, const int lineNum) - { - if (err == noErr) - return true; - - Logger::writeToLog ("CoreAudio error: " + String (lineNum) + " - " + String::toHexString ((int) err)); - return false; - } - - #define OK(a) logAnyErrors_CoreAudio (a, __LINE__) -#else - #define OK(a) (a == noErr) + #define JUCE_COREAUDIOLOG(a) #endif class CoreAudioInternal : public Timer @@ -284447,7 +284328,7 @@ public: rates << sampleRate; } - log ("sr: " + rates); + JUCE_COREAUDIOLOG ("sr: " + rates); inputLatency = 0; outputLatency = 0; @@ -284464,7 +284345,7 @@ public: if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr) outputLatency = (int) lat; - log ("lat: " + String (inputLatency) + " " + String (outputLatency)); + JUCE_COREAUDIOLOG ("lat: " + String (inputLatency) + " " + String (outputLatency)); inChanNames.clear(); outChanNames.clear(); @@ -284571,7 +284452,7 @@ public: int bufferSizeSamples) { String error; - log ("CoreAudio reopen"); + JUCE_COREAUDIOLOG ("CoreAudio reopen"); callbacksAllowed = false; stopTimer(); @@ -284645,11 +284526,11 @@ public: if (deviceID != 0) { -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 if (OK (AudioDeviceAddIOProc (deviceID, audioIOProc, this))) -#else + #else if (OK (AudioDeviceCreateIOProcID (deviceID, audioIOProc, this, &audioProcID))) -#endif + #endif { if (OK (AudioDeviceStart (deviceID, audioIOProc))) { @@ -284657,12 +284538,12 @@ public: } else { -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 OK (AudioDeviceRemoveIOProc (deviceID, audioIOProc)); -#else + #else OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID)); audioProcID = 0; -#endif + #endif } } } @@ -284674,10 +284555,7 @@ public: callback = cb; } - if (inputDevice != nullptr) - return started && inputDevice->start (cb); - else - return started; + return started && (inputDevice == nullptr || inputDevice->start (cb)); } void stop (bool leaveInterruptRunning) @@ -284693,12 +284571,13 @@ public: { OK (AudioDeviceStop (deviceID, audioIOProc)); -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 OK (AudioDeviceRemoveIOProc (deviceID, audioIOProc)); -#else + #else OK (AudioDeviceDestroyIOProcID (deviceID, audioProcID)); audioProcID = 0; -#endif + #endif + started = false; { const ScopedLock sl (callbackLock); } @@ -284729,15 +284608,8 @@ public: inputDevice->stop (leaveInterruptRunning); } - double getSampleRate() const - { - return sampleRate; - } - - int getBufferSize() const - { - return bufferSize; - } + double getSampleRate() const { return sampleRate; } + int getBufferSize() const { return bufferSize; } void audioCallback (const AudioBufferList* inInputData, AudioBufferList* outOutputData) @@ -284844,7 +284716,7 @@ public: void timerCallback() { stopTimer(); - log ("CoreAudio device changed callback"); + JUCE_COREAUDIOLOG ("CoreAudio device changed callback"); const double oldSampleRate = sampleRate; const int oldBufferSize = bufferSize; @@ -284907,9 +284779,9 @@ public: Array sampleRates; Array bufferSizes; AudioIODeviceCallback* callback; -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 AudioDeviceIOProcID audioProcID; -#endif + #endif ScopedPointer inputDevice; bool isSlaveDevice; @@ -284982,17 +284854,31 @@ private: UInt32 size = 0; if (deviceID != 0 - && OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) + && AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr) { types.calloc (size, 1); - if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types))) + if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, types) == noErr) return size / (int) sizeof (OSType); } return 0; } + bool OK (const OSStatus errorCode) const + { + if (errorCode == noErr) + return true; + + const String errorMessage ("CoreAudio error: " + String::toHexString ((int) errorCode)); + JUCE_COREAUDIOLOG (errorMessage); + + if (callback != nullptr) + callback->audioDeviceError (errorMessage); + + return false; + } + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreAudioInternal); }; @@ -285032,6 +284918,7 @@ public: } internal = device; + jassert (device != nullptr); AudioObjectPropertyAddress pa; pa.mSelector = kAudioObjectPropertySelectorWildcard; @@ -285066,25 +284953,17 @@ public: return internal->inChanNames; } - int getNumSampleRates() - { - return internal->sampleRates.size(); - } + bool isOpen() { return isOpen_; } - double getSampleRate (int index) - { - return internal->sampleRates [index]; - } + int getNumSampleRates() { return internal->sampleRates.size(); } + double getSampleRate (int index) { return internal->sampleRates [index]; } + double getCurrentSampleRate() { return internal->getSampleRate(); } - int getNumBufferSizesAvailable() - { - return internal->bufferSizes.size(); - } + int getCurrentBitDepth() { return 32; } // no way to find out, so just assume it's high.. - int getBufferSizeSamples (int index) - { - return internal->bufferSizes [index]; - } + int getNumBufferSizesAvailable() { return internal->bufferSizes.size(); } + int getBufferSizeSamples (int index) { return internal->bufferSizes [index]; } + int getCurrentBufferSizeSamples() { return internal->getBufferSize(); } int getDefaultBufferSize() { @@ -285116,51 +284995,23 @@ public: internal->stop (false); } - bool isOpen() - { - return isOpen_; - } - - int getCurrentBufferSizeSamples() - { - return internal != nullptr ? internal->getBufferSize() : 512; - } - - double getCurrentSampleRate() - { - return internal != nullptr ? internal->getSampleRate() : 0; - } - - int getCurrentBitDepth() - { - return 32; // no way to find out, so just assume it's high.. - } - const BigInteger getActiveOutputChannels() const { - return internal != nullptr ? internal->activeOutputChans : BigInteger(); + return internal->activeOutputChans; } const BigInteger getActiveInputChannels() const { - BigInteger chans; - - if (internal != nullptr) - { - chans = internal->activeInputChans; + BigInteger chans (internal->activeInputChans); - if (internal->inputDevice != 0) - chans |= internal->inputDevice->activeInputChans; - } + if (internal->inputDevice != nullptr) + chans |= internal->inputDevice->activeInputChans; return chans; } int getOutputLatencyInSamples() { - if (internal == nullptr) - return 0; - // this seems like a good guess at getting the latency right - comparing // this with a round-trip measurement, it gets it to within a few millisecs // for the built-in mac soundcard @@ -285169,15 +285020,12 @@ public: int getInputLatencyInSamples() { - if (internal == nullptr) - return 0; - return internal->inputLatency + internal->getBufferSize() * 2; } void start (AudioIODeviceCallback* callback) { - if (internal != nullptr && ! isStarted) + if (! isStarted) { if (callback != nullptr) callback->audioDeviceAboutToStart (this); @@ -285189,7 +285037,7 @@ public: void stop() { - if (isStarted && internal != nullptr) + if (isStarted) { AudioIODeviceCallback* const lastCallback = internal->callback; @@ -285253,10 +285101,6 @@ public: { } - ~CoreAudioIODeviceType() - { - } - void scanForDevices() { hasScanned = true; @@ -285273,12 +285117,12 @@ public: pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = kAudioObjectPropertyElementMaster; - if (OK (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size))) + if (AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, &pa, 0, 0, &size) == noErr) { HeapBlock devs; devs.calloc (size, 1); - if (OK (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs))) + if (AudioObjectGetPropertyData (kAudioObjectSystemObject, &pa, 0, 0, &size, devs) == noErr) { const int num = size / (int) sizeof (AudioDeviceID); for (int i = 0; i < num; ++i) @@ -285287,7 +285131,7 @@ public: size = sizeof (name); pa.mSelector = kAudioDevicePropertyDeviceName; - if (OK (AudioObjectGetPropertyData (devs[i], &pa, 0, 0, &size, name))) + if (AudioObjectGetPropertyData (devs[i], &pa, 0, 0, &size, name) == noErr) { const String nameString (String::fromUTF8 (name, (int) strlen (name))); const int numIns = getNumChannels (devs[i], true); @@ -285317,10 +285161,8 @@ public: { jassert (hasScanned); // need to call scanForDevices() before doing this - if (wantInputNames) - return inputDeviceNames; - else - return outputDeviceNames; + return wantInputNames ? inputDeviceNames + : outputDeviceNames; } int getDefaultDeviceIndex (bool forInput) const @@ -285409,12 +285251,12 @@ private: pa.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; pa.mElement = kAudioObjectPropertyElementMaster; - if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) + if (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size) == noErr) { HeapBlock bufList; bufList.calloc (size, 1); - if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) + if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList) == noErr) { const int numStreams = bufList->mNumberBuffers; @@ -285437,7 +285279,7 @@ AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_CoreAudio() return new CoreAudioIODeviceType(); } -#undef log +#undef JUCE_COREAUDIOLOG #endif diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 09f0ef004c..c901c56b7f 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 89 +#define JUCE_BUILDNUMBER 90 /** Current Juce version number. @@ -1647,8 +1647,8 @@ public: template static double readDoubleValue (CharPointerType& text) noexcept { - double result[3] = { 0, 0, 0 }, accumulator[2] = { 0, 0 }; - int exponentAdjustment[2] = { 0, 0 }, exponentAccumulator[2] = { -1, -1 }; + double result[3] = { 0 }, accumulator[2] = { 0 }; + int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 }; int exponent = 0, decPointIndex = 0, digit = 0; int lastDigit = 0, numSignificantDigits = 0; bool isNegative = false, digitsFound = false; @@ -8734,16 +8734,16 @@ public: var (ReferenceCountedObject* object); var (MethodFunction method) noexcept; - var& operator= (const var& valueToCopy); - var& operator= (int value); - var& operator= (int64 value); - var& operator= (bool value); - var& operator= (double value); - var& operator= (const char* value); - var& operator= (const wchar_t* value); - var& operator= (const String& value); - var& operator= (ReferenceCountedObject* object); - var& operator= (MethodFunction method); + const var& operator= (const var& valueToCopy); + const var& operator= (int value); + const var& operator= (int64 value); + const var& operator= (bool value); + const var& operator= (double value); + const var& operator= (const char* value); + const var& operator= (const wchar_t* value); + const var& operator= (const String& value); + const var& operator= (ReferenceCountedObject* object); + const var& operator= (MethodFunction method); void swapWith (var& other) noexcept; @@ -18835,6 +18835,8 @@ private: bool negative; void ensureSize (int numVals); + void shiftLeft (int bits, int startBit); + void shiftRight (int bits, int startBit); static const BigInteger simpleGCD (BigInteger* m, BigInteger* n); static inline int bitToIndex (const int bit) noexcept { return bit >> 5; } @@ -19258,6 +19260,7 @@ private: void openHandle(); void closeHandle(); void flushInternal(); + bool flushBuffer(); int64 setPositionInternal (int64 newPosition); int writeInternal (const void* data, int numBytes); @@ -20835,6 +20838,7 @@ private: friend class ScopedPointer ; ScopedPointer helper; bool doNextBlock(); + void flushInternal(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); }; @@ -21077,6 +21081,8 @@ private: MemoryBlock internalBlock; size_t position, size; + void trimExternalBlockSize(); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); }; @@ -38124,9 +38130,14 @@ public: */ virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; - /** Called to indicate that the device has stopped. - */ + /** Called to indicate that the device has stopped. */ virtual void audioDeviceStopped() = 0; + + /** This can be overridden to be told if the device generates an error while operating. + Be aware that this could be called by any thread! And not all devices perform + this callback. + */ + virtual void audioDeviceError (const String& errorMessage); }; /** @@ -38728,6 +38739,8 @@ private: int blockSize, readAheadBufferSize; bool isPrepared, inputStreamEOF; + void releaseMasterResources(); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); }; @@ -42920,6 +42933,27 @@ public: /** @internal */ void setTemporaryUnderlining (const Array >&); + bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); + bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); + bool moveCaretUp (bool selecting); + bool moveCaretDown (bool selecting); + bool pageUp (bool selecting); + bool pageDown (bool selecting); + bool scrollDown(); + bool scrollUp(); + bool moveCaretToTop (bool selecting); + bool moveCaretToStartOfLine (bool selecting); + bool moveCaretToEnd (bool selecting); + bool moveCaretToEndOfLine (bool selecting); + bool deleteBackwards (bool moveInWholeWordSteps); + bool deleteForwards (bool moveInWholeWordSteps); + bool copyToClipboard(); + bool cutToClipboard(); + bool pasteFromClipboard(); + bool selectAll(); + bool undo(); + bool redo(); + /** This adds the items to the popup menu. By default it adds the cut/copy/paste items, but you can override this if @@ -43052,7 +43086,7 @@ private: int indexAtPosition (float x, float y); int findWordBreakAfter (int position) const; int findWordBreakBefore (int position) const; - + bool moveCaretWithTransation (int newPos, bool selecting); friend class TextHolderComponent; friend class TextEditorViewport; void drawContent (Graphics& g); @@ -43060,6 +43094,8 @@ private: float getWordWrapWidth() const; void timerCallbackInt(); void repaintText (const Range& range); + void scrollByLines (int deltaLines); + bool undoOrRedo (bool shouldUndo); UndoManager* getUndoManager() noexcept; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextEditor); @@ -47364,6 +47400,7 @@ private: void scanFor (AudioPluginFormat* format); static void optionsMenuStaticCallback (int result, PluginListComponent*); void optionsMenuCallback (int result); + void updateList(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); }; @@ -49522,6 +49559,8 @@ private: Path path; int offset; + void updateShadowAndOffset(); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton); }; @@ -52238,40 +52277,36 @@ public: */ const CodeDocument::Position getPositionAt (int x, int y); - void cursorLeft (bool moveInWholeWordSteps, bool selecting); - void cursorRight (bool moveInWholeWordSteps, bool selecting); - void cursorDown (bool selecting); - void cursorUp (bool selecting); + bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); + bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); + bool moveCaretUp (bool selecting); + bool moveCaretDown (bool selecting); + bool scrollDown(); + bool scrollUp(); + bool pageUp (bool selecting); + bool pageDown (bool selecting); + bool moveCaretToTop (bool selecting); + bool moveCaretToStartOfLine (bool selecting); + bool moveCaretToEnd (bool selecting); + bool moveCaretToEndOfLine (bool selecting); + bool deleteBackwards (bool moveInWholeWordSteps); + bool deleteForwards (bool moveInWholeWordSteps); + bool copyToClipboard(); + bool cutToClipboard(); + bool pasteFromClipboard(); + bool undo(); + bool redo(); - void pageDown (bool selecting); - void pageUp (bool selecting); + bool selectAll(); + void deselectAll(); - void scrollDown(); - void scrollUp(); void scrollToLine (int newFirstLineOnScreen); void scrollBy (int deltaLines); void scrollToColumn (int newFirstColumnOnScreen); void scrollToKeepCaretOnScreen(); - void goToStartOfDocument (bool selecting); - void goToStartOfLine (bool selecting); - void goToEndOfDocument (bool selecting); - void goToEndOfLine (bool selecting); - - void deselectAll(); - void selectAll(); - void insertTextAtCaret (const String& textToInsert); void insertTabAtCaret(); - void cut(); - void copy(); - void copyThenCut(); - void paste(); - void backspace (bool moveInWholeWordSteps); - void deleteForward (bool moveInWholeWordSteps); - - void undo(); - void redo(); const Range getHighlightedRegion() const; void setHighlightedRegion (const Range& newRange); @@ -52422,6 +52457,7 @@ private: void scrollToLineInternal (int line); void scrollToColumnInternal (double column); void newTransaction(); + void cut(); int indexToColumn (int line, int index) const noexcept; int columnToIndex (int line, int column) const noexcept; @@ -53426,7 +53462,8 @@ private: double velocityModeSensitivity, velocityModeOffset, minMaxDiff; int velocityModeThreshold; float rotaryStart, rotaryEnd; - int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged; + int numDecimalPlaces; + Point mousePosWhenLastDragged; int mouseDragStartX, mouseDragStartY; int sliderRegionStart, sliderRegionSize; int sliderBeingDragged; @@ -55763,6 +55800,9 @@ protected: */ virtual void getRoots (StringArray& rootNames, StringArray& rootPaths); + /** Updates the items in the dropdown list of recent paths with the values from getRoots(). */ + void resetRecentPaths(); + private: ScopedPointer fileList; @@ -56995,6 +57035,7 @@ private: bool hasBeenResized; #endif + void initialise (bool addToDesktop); void updateLastPos(); void setContent (Component* newComp, bool takeOwnership, bool resizeToFit); @@ -58863,6 +58904,340 @@ private: #endif #ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ +#endif +#ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ + +/*** Start of inlined file: juce_TextEditorKeyMapper.h ***/ +#ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ +#define __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ + + +/*** Start of inlined file: juce_Keypress.h ***/ +#ifndef __JUCE_KEYPRESS_JUCEHEADER__ +#define __JUCE_KEYPRESS_JUCEHEADER__ + +/** + Represents a key press, including any modifier keys that are needed. + + E.g. a KeyPress might represent CTRL+C, SHIFT+ALT+H, Spacebar, Escape, etc. + + @see Component, KeyListener, Button::addShortcut, KeyPressMappingManager +*/ +class JUCE_API KeyPress +{ +public: + + /** Creates an (invalid) KeyPress. + + @see isValid + */ + KeyPress() noexcept; + + /** Creates a KeyPress for a key and some modifiers. + + 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 + */ + KeyPress (int keyCode, + const ModifierKeys& modifiers, + juce_wchar textCharacter) noexcept; + + /** Creates a keypress with a keyCode but no modifiers or text character. + */ + KeyPress (int keyCode) noexcept; + + /** Creates a copy of another KeyPress. */ + KeyPress (const KeyPress& other) noexcept; + + /** Copies this KeyPress from another one. */ + KeyPress& operator= (const KeyPress& other) noexcept; + + /** Compares two KeyPress objects. */ + bool operator== (const KeyPress& other) const noexcept; + + /** Compares two KeyPress objects. */ + bool operator!= (const KeyPress& other) const noexcept; + + /** Returns true if this is a valid KeyPress. + + A null keypress can be created by the default constructor, in case it's + needed. + */ + bool isValid() const noexcept { return keyCode != 0; } + + /** Returns the key code itself. + + This will either be one of the special constants defined in this class, + or an 8-bit character code. + */ + int getKeyCode() const noexcept { return keyCode; } + + /** Returns the key modifiers. + + @see ModifierKeys + */ + const ModifierKeys getModifiers() const noexcept { return mods; } + + /** Returns the character that is associated with this keypress. + + 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 noexcept { return textCharacter; } + + /** Checks whether the KeyPress's key is the same as the one provided, without checking + the modifiers. + + The values for key codes can either be one of the special constants defined in + this class, or an 8-bit character code. + + @see getKeyCode + */ + bool isKeyCode (int keyCodeToCompare) const noexcept { return keyCode == keyCodeToCompare; } + + /** Converts a textual key description to a KeyPress. + + This attempts to decode a textual version of a keypress, e.g. "CTRL + C" or "SPACE". + + This isn't designed to cope with any kind of input, but should be given the + strings that are created by the getTextDescription() method. + + If the string can't be parsed, the object returned will be invalid. + + @see getTextDescription + */ + static const KeyPress createFromDescription (const String& textVersion); + + /** Creates a textual description of the key combination. + + e.g. "CTRL + C" or "DELETE". + + To store a keypress in a file, use this method, along with createFromDescription() + to retrieve it later. + */ + const String getTextDescription() const; + + /** Creates a textual description of the key combination, using unicode icon symbols if possible. + + On OSX, this uses the Apple symbols for command, option, shift, etc, instead of the textual + modifier key descriptions that are returned by getTextDescription() + */ + const String getTextDescriptionWithIcons() const; + + /** Checks whether the user is currently holding down the keys that make up this + KeyPress. + + 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; + + /** Checks whether a particular key is held down, irrespective of modifiers. + + 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); + + // 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. + // + + 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*/ + + 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 */ + + 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 */ + + 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 */ + + 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. */ + + 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. */ + + 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: + + int keyCode; + ModifierKeys mods; + juce_wchar textCharacter; + + JUCE_LEAK_DETECTOR (KeyPress); +}; + +#endif // __JUCE_KEYPRESS_JUCEHEADER__ + +/*** End of inlined file: juce_Keypress.h ***/ + +/** This class is used to invoke a range of text-editor navigation methods on + an object, based upon a keypress event. + + It's currently used internally by the TextEditor and CodeEditorComponent. +*/ +template +struct TextEditorKeyMapper +{ + /** Checks the keypress and invokes one of a range of navigation functions that + the target class must implement, based on the key event. + */ + static bool invokeKeyFunction (CallbackClass& target, const KeyPress& key) + { + const bool isShiftDown = key.getModifiers().isShiftDown(); + const bool ctrlOrAltDown = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown(); + + if (key == KeyPress (KeyPress::downKey, ModifierKeys::ctrlModifier, 0) + && target.scrollUp()) + return true; + + if (key == KeyPress (KeyPress::upKey, ModifierKeys::ctrlModifier, 0) + && target.scrollDown()) + return true; + + #if JUCE_MAC + if (key.getModifiers().isCommandDown()) + { + if (key.isKeyCode (KeyPress::upKey)) + return target.moveCaretToTop (isShiftDown); + + if (key.isKeyCode (KeyPress::downKey)) + return target.moveCaretToEnd (isShiftDown); + + if (key.isKeyCode (KeyPress::leftKey)) + return target.moveCaretToStartOfLine (isShiftDown); + + if (key.isKeyCode (KeyPress::rightKey)) + return target.moveCaretToEndOfLine (isShiftDown); + } + #endif + + if (key.isKeyCode (KeyPress::upKey)) + return target.moveCaretUp (isShiftDown); + + if (key.isKeyCode (KeyPress::downKey)) + return target.moveCaretDown (isShiftDown); + + if (key.isKeyCode (KeyPress::leftKey)) + return target.moveCaretLeft (ctrlOrAltDown, isShiftDown); + + if (key.isKeyCode (KeyPress::rightKey)) + return target.moveCaretRight (ctrlOrAltDown, isShiftDown); + + if (key.isKeyCode (KeyPress::pageUpKey)) + return target.pageUp (isShiftDown); + + if (key.isKeyCode (KeyPress::pageDownKey)) + return target.pageDown (isShiftDown); + + if (key.isKeyCode (KeyPress::homeKey)) + return ctrlOrAltDown ? target.moveCaretToTop (isShiftDown) + : target.moveCaretToStartOfLine (isShiftDown); + + if (key.isKeyCode (KeyPress::endKey)) + return ctrlOrAltDown ? target.moveCaretToEnd (isShiftDown) + : target.moveCaretToEndOfLine (isShiftDown); + + if (key == KeyPress ('c', ModifierKeys::commandModifier, 0) + || key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0)) + return target.copyToClipboard(); + + if (key == KeyPress ('x', ModifierKeys::commandModifier, 0) + || key == KeyPress (KeyPress::deleteKey, ModifierKeys::shiftModifier, 0)) + return target.cutToClipboard(); + + if (key == KeyPress ('v', ModifierKeys::commandModifier, 0) + || key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0)) + return target.pasteFromClipboard(); + + if (key.isKeyCode (KeyPress::backspaceKey)) + return target.deleteBackwards (ctrlOrAltDown); + + if (key.isKeyCode (KeyPress::deleteKey)) + return target.deleteForwards (ctrlOrAltDown); + + if (key == KeyPress ('a', ModifierKeys::commandModifier, 0)) + return target.selectAll(); + + if (key == KeyPress ('z', ModifierKeys::commandModifier, 0)) + return target.undo(); + + if (key == KeyPress ('y', ModifierKeys::commandModifier, 0) + || key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0)) + return target.redo(); + + return false; + } +}; + +#endif // __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__ + +/*** End of inlined file: juce_TextEditorKeyMapper.h ***/ + + #endif #ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__ @@ -63088,6 +63463,8 @@ private: ScopedPointer midiOutputSelector; ScopedPointer