| @@ -32,6 +32,7 @@ SynthesiserVoice::SynthesiserVoice() | |||||
| currentPlayingMidiChannel (0), | currentPlayingMidiChannel (0), | ||||
| noteOnTime (0), | noteOnTime (0), | ||||
| keyIsDown (false), | keyIsDown (false), | ||||
| sustainPedalDown (false), | |||||
| sostenutoPedalDown (false) | sostenutoPedalDown (false) | ||||
| { | { | ||||
| } | } | ||||
| @@ -296,6 +297,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice, | |||||
| voice->currentlyPlayingSound = sound; | voice->currentlyPlayingSound = sound; | ||||
| voice->keyIsDown = true; | voice->keyIsDown = true; | ||||
| voice->sostenutoPedalDown = false; | voice->sostenutoPedalDown = false; | ||||
| voice->sustainPedalDown = sustainPedalsDown[midiChannel]; | |||||
| voice->startNote (midiNoteNumber, velocity, sound, | voice->startNote (midiNoteNumber, velocity, sound, | ||||
| lastPitchWheelValues [midiChannel - 1]); | lastPitchWheelValues [midiChannel - 1]); | ||||
| @@ -331,9 +333,11 @@ void Synthesiser::noteOff (const int midiChannel, | |||||
| if (sound->appliesToNote (midiNoteNumber) | if (sound->appliesToNote (midiNoteNumber) | ||||
| && sound->appliesToChannel (midiChannel)) | && sound->appliesToChannel (midiChannel)) | ||||
| { | { | ||||
| jassert (! voice->keyIsDown || voice->sustainPedalDown == sustainPedalsDown [midiChannel]); | |||||
| voice->keyIsDown = false; | voice->keyIsDown = false; | ||||
| if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown)) | |||||
| if (! (voice->sustainPedalDown || voice->sostenutoPedalDown)) | |||||
| stopVoice (voice, velocity, allowTailOff); | stopVoice (voice, velocity, allowTailOff); | ||||
| } | } | ||||
| } | } | ||||
| @@ -427,6 +431,14 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) | |||||
| if (isDown) | if (isDown) | ||||
| { | { | ||||
| sustainPedalsDown.setBit (midiChannel); | sustainPedalsDown.setBit (midiChannel); | ||||
| for (int i = voices.size(); --i >= 0;) | |||||
| { | |||||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | |||||
| if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown()) | |||||
| voice->sustainPedalDown = true; | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -434,8 +446,13 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) | |||||
| { | { | ||||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | SynthesiserVoice* const voice = voices.getUnchecked (i); | ||||
| if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown) | |||||
| stopVoice (voice, 1.0f, true); | |||||
| if (voice->isPlayingChannel (midiChannel)) | |||||
| { | |||||
| voice->sustainPedalDown = false; | |||||
| if (! voice->isKeyDown()) | |||||
| stopVoice (voice, 1.0f, true); | |||||
| } | |||||
| } | } | ||||
| sustainPedalsDown.clearBit (midiChannel); | sustainPedalsDown.clearBit (midiChannel); | ||||
| @@ -505,8 +522,13 @@ struct VoiceAgeSorter | |||||
| SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | ||||
| int /*midiChannel*/, int midiNoteNumber) const | int /*midiChannel*/, int midiNoteNumber) const | ||||
| { | { | ||||
| SynthesiserVoice* bottom = nullptr; | |||||
| SynthesiserVoice* top = nullptr; | |||||
| // This voice-stealing algorithm applies the following heuristics: | |||||
| // - Re-use the oldest notes first | |||||
| // - Protect the lowest & topmost notes, even if sustained, but not if they've been released. | |||||
| // These are the voices we want to protect (ie: only steal if unavoidable) | |||||
| SynthesiserVoice* low = nullptr; // Lowest sounding note, might be sustained, but NOT in release phase | |||||
| SynthesiserVoice* top = nullptr; // Highest sounding note, might be sustained, but NOT in release phase | |||||
| // this is a list of voices we can steal, sorted by how long they've been running | // this is a list of voices we can steal, sorted by how long they've been running | ||||
| Array<SynthesiserVoice*> usableVoices; | Array<SynthesiserVoice*> usableVoices; | ||||
| @@ -516,24 +538,33 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||||
| { | { | ||||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | SynthesiserVoice* const voice = voices.getUnchecked (i); | ||||
| jassert (voice->isVoiceActive()); // We wouldn't be here otherwise | |||||
| if (voice->canPlaySound (soundToPlay)) | if (voice->canPlaySound (soundToPlay)) | ||||
| { | { | ||||
| VoiceAgeSorter sorter; | VoiceAgeSorter sorter; | ||||
| usableVoices.addSorted (sorter, voice); | usableVoices.addSorted (sorter, voice); | ||||
| const int note = voice->getCurrentlyPlayingNote(); | |||||
| if (! voice->isPlayingButReleased()) // Don't protect released notes | |||||
| { | |||||
| const int note = voice->getCurrentlyPlayingNote(); | |||||
| if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote()) | |||||
| bottom = voice; | |||||
| if (low == nullptr || note < low->getCurrentlyPlayingNote()) | |||||
| low = voice; | |||||
| if (top == nullptr || note > top->getCurrentlyPlayingNote()) | |||||
| top = voice; | |||||
| if (top == nullptr || note > top->getCurrentlyPlayingNote()) | |||||
| top = voice; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| // Eliminate pathological cases (ie: only 1 note playing): we always give precedence to the lowest note(s) | |||||
| if (top == low) | |||||
| top = nullptr; | |||||
| const int numUsableVoices = usableVoices.size(); | const int numUsableVoices = usableVoices.size(); | ||||
| // The oldest note that's playing with the target pitch playing is ideal.. | |||||
| // The oldest note that's playing with the target pitch is ideal.. | |||||
| for (int i = 0; i < numUsableVoices; ++i) | for (int i = 0; i < numUsableVoices; ++i) | ||||
| { | { | ||||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | ||||
| @@ -547,7 +578,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||||
| { | { | ||||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | ||||
| if (voice != bottom && voice != top && ! voice->isKeyDown() && ! voice->isSostenutoPedalDown()) | |||||
| if (voice != low && voice != top && voice->isPlayingButReleased()) | |||||
| return voice; | return voice; | ||||
| } | } | ||||
| @@ -556,21 +587,25 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||||
| { | { | ||||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | ||||
| if (voice != bottom && voice != top && ! voice->isKeyDown()) | |||||
| if (voice != low && voice != top && ! voice->isKeyDown()) | |||||
| return voice; | return voice; | ||||
| } | } | ||||
| // At this point, all notes have fingers on them, so look for the oldest note | |||||
| // that isn't the top or bottom note.. | |||||
| // Oldest voice that isn't protected | |||||
| for (int i = 0; i < numUsableVoices; ++i) | for (int i = 0; i < numUsableVoices; ++i) | ||||
| { | { | ||||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | ||||
| if (voice != bottom && voice != top) | |||||
| if (voice != low && voice != top) | |||||
| return voice; | return voice; | ||||
| } | } | ||||
| // ..otherwise, there's only one or two voices to choose from - prefer to steal the highest one: | |||||
| jassert (top != nullptr || bottom != nullptr); | |||||
| return (top == nullptr ? bottom : top); | |||||
| // We've only got "protected" voices now: lowest note takes priority | |||||
| jassert (low != nullptr); | |||||
| // Duophonic synth: give priority to the bass note: | |||||
| if (top != nullptr) | |||||
| return top; | |||||
| return low; | |||||
| } | } | ||||
| @@ -214,9 +214,18 @@ public: | |||||
| */ | */ | ||||
| bool isKeyDown() const noexcept { return keyIsDown; } | bool isKeyDown() const noexcept { return keyIsDown; } | ||||
| /** Returns true if the sustain pedal is currently active for this voice. */ | |||||
| bool isSustainPedalDown() const noexcept { return sustainPedalDown; } | |||||
| /** Returns true if the sostenuto pedal is currently active for this voice. */ | /** Returns true if the sostenuto pedal is currently active for this voice. */ | ||||
| bool isSostenutoPedalDown() const noexcept { return sostenutoPedalDown; } | bool isSostenutoPedalDown() const noexcept { return sostenutoPedalDown; } | ||||
| /** Returns true if a voice is sounding in its release phase **/ | |||||
| bool isPlayingButReleased() const noexcept | |||||
| { | |||||
| return isVoiceActive() && ! (isKeyDown() || isSostenutoPedalDown() || isSustainPedalDown()); | |||||
| } | |||||
| /** Returns true if this voice started playing its current note before the other voice did. */ | /** Returns true if this voice started playing its current note before the other voice did. */ | ||||
| bool wasStartedBefore (const SynthesiserVoice& other) const noexcept; | bool wasStartedBefore (const SynthesiserVoice& other) const noexcept; | ||||
| @@ -244,7 +253,7 @@ private: | |||||
| int currentlyPlayingNote, currentPlayingMidiChannel; | int currentlyPlayingNote, currentPlayingMidiChannel; | ||||
| uint32 noteOnTime; | uint32 noteOnTime; | ||||
| SynthesiserSound::Ptr currentlyPlayingSound; | SynthesiserSound::Ptr currentlyPlayingSound; | ||||
| bool keyIsDown, sostenutoPedalDown; | |||||
| bool keyIsDown, sustainPedalDown, sostenutoPedalDown; | |||||
| #if JUCE_CATCH_DEPRECATED_CODE_MISUSE | #if JUCE_CATCH_DEPRECATED_CODE_MISUSE | ||||
| // Note the new parameters for this method. | // Note the new parameters for this method. | ||||
| @@ -486,14 +486,17 @@ public: | |||||
| sampleRate = newSampleRate; | sampleRate = newSampleRate; | ||||
| bufferSize = newBufferSize; | bufferSize = newBufferSize; | ||||
| inputChannelBuffer.setSize (jmax ((int) minChansIn, inputChannels.getHighestBit()) + 1, bufferSize); | |||||
| int maxInputsRequested = inputChannels.getHighestBit() + 1; | |||||
| maxInputsRequested = jmax ((int) minChansIn, jmin ((int) maxChansIn, maxInputsRequested)); | |||||
| inputChannelBuffer.setSize (maxInputsRequested, bufferSize); | |||||
| inputChannelBuffer.clear(); | inputChannelBuffer.clear(); | ||||
| inputChannelDataForCallback.clear(); | inputChannelDataForCallback.clear(); | ||||
| currentInputChans.clear(); | currentInputChans.clear(); | ||||
| if (inputChannels.getHighestBit() >= 0) | if (inputChannels.getHighestBit() >= 0) | ||||
| { | { | ||||
| for (int i = 0; i <= jmax (inputChannels.getHighestBit(), (int) minChansIn); ++i) | |||||
| for (int i = 0; i < maxInputsRequested; ++i) | |||||
| { | { | ||||
| if (inputChannels[i]) | if (inputChannels[i]) | ||||
| { | { | ||||
| @@ -505,14 +508,17 @@ public: | |||||
| ensureMinimumNumBitsSet (outputChannels, (int) minChansOut); | ensureMinimumNumBitsSet (outputChannels, (int) minChansOut); | ||||
| outputChannelBuffer.setSize (jmax ((int) minChansOut, outputChannels.getHighestBit()) + 1, bufferSize); | |||||
| int maxOutputsRequested = outputChannels.getHighestBit() + 1; | |||||
| maxOutputsRequested = jmax ((int) minChansOut, jmin ((int) maxChansOut, maxOutputsRequested)); | |||||
| outputChannelBuffer.setSize (maxOutputsRequested, bufferSize); | |||||
| outputChannelBuffer.clear(); | outputChannelBuffer.clear(); | ||||
| outputChannelDataForCallback.clear(); | outputChannelDataForCallback.clear(); | ||||
| currentOutputChans.clear(); | currentOutputChans.clear(); | ||||
| if (outputChannels.getHighestBit() >= 0) | if (outputChannels.getHighestBit() >= 0) | ||||
| { | { | ||||
| for (int i = 0; i <= jmax (outputChannels.getHighestBit(), (int) minChansOut); ++i) | |||||
| for (int i = 0; i < maxOutputsRequested; ++i) | |||||
| { | { | ||||
| if (outputChannels[i]) | if (outputChannels[i]) | ||||
| { | { | ||||
| @@ -796,10 +802,10 @@ class ALSAAudioIODevice : public AudioIODevice | |||||
| { | { | ||||
| public: | public: | ||||
| ALSAAudioIODevice (const String& deviceName, | ALSAAudioIODevice (const String& deviceName, | ||||
| const String& typeName, | |||||
| const String& deviceTypeName, | |||||
| const String& inputDeviceID, | const String& inputDeviceID, | ||||
| const String& outputDeviceID) | const String& outputDeviceID) | ||||
| : AudioIODevice (deviceName, typeName), | |||||
| : AudioIODevice (deviceName, deviceTypeName), | |||||
| inputId (inputDeviceID), | inputId (inputDeviceID), | ||||
| outputId (outputDeviceID), | outputId (outputDeviceID), | ||||
| isOpen_ (false), | isOpen_ (false), | ||||
| @@ -924,8 +930,8 @@ private: | |||||
| class ALSAAudioIODeviceType : public AudioIODeviceType | class ALSAAudioIODeviceType : public AudioIODeviceType | ||||
| { | { | ||||
| public: | public: | ||||
| ALSAAudioIODeviceType (bool onlySoundcards, const String &typeName) | |||||
| : AudioIODeviceType (typeName), | |||||
| ALSAAudioIODeviceType (bool onlySoundcards, const String &deviceTypeName) | |||||
| : AudioIODeviceType (deviceTypeName), | |||||
| hasScanned (false), | hasScanned (false), | ||||
| listOnlySoundcards (onlySoundcards) | listOnlySoundcards (onlySoundcards) | ||||
| { | { | ||||
| @@ -277,7 +277,7 @@ public: | |||||
| if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ranges))) | if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, ranges))) | ||||
| { | { | ||||
| static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 }; | |||||
| static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, 384000.0 }; | |||||
| for (int i = 0; i < numElementsInArray (possibleRates); ++i) | for (int i = 0; i < numElementsInArray (possibleRates); ++i) | ||||
| { | { | ||||
| @@ -45,6 +45,14 @@ namespace CoreMidiHelpers | |||||
| #define CHECK_ERROR(a) CoreMidiHelpers::checkError (a, __LINE__) | #define CHECK_ERROR(a) CoreMidiHelpers::checkError (a, __LINE__) | ||||
| //============================================================================== | //============================================================================== | ||||
| struct ScopedCFString | |||||
| { | |||||
| ScopedCFString() noexcept : cfString (nullptr) {} | |||||
| ~ScopedCFString() noexcept { if (cfString != nullptr) CFRelease (cfString); } | |||||
| CFStringRef cfString; | |||||
| }; | |||||
| static String getMidiObjectName (MIDIObjectRef entity) | static String getMidiObjectName (MIDIObjectRef entity) | ||||
| { | { | ||||
| String result; | String result; | ||||
| @@ -116,7 +124,7 @@ namespace CoreMidiHelpers | |||||
| if (numConnections > 0) | if (numConnections > 0) | ||||
| { | { | ||||
| const SInt32* pid = reinterpret_cast <const SInt32*> (CFDataGetBytePtr (connections)); | |||||
| const SInt32* pid = reinterpret_cast<const SInt32*> (CFDataGetBytePtr (connections)); | |||||
| for (int i = 0; i < numConnections; ++i, ++pid) | for (int i = 0; i < numConnections; ++i, ++pid) | ||||
| { | { | ||||
| @@ -133,7 +141,7 @@ namespace CoreMidiHelpers | |||||
| || connObjectType == kMIDIObjectType_ExternalDestination) | || connObjectType == kMIDIObjectType_ExternalDestination) | ||||
| { | { | ||||
| // Connected to an external device's endpoint (10.3 and later). | // Connected to an external device's endpoint (10.3 and later). | ||||
| s = getEndpointName (static_cast <MIDIEndpointRef> (connObject), true); | |||||
| s = getEndpointName (static_cast<MIDIEndpointRef> (connObject), true); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -208,9 +216,9 @@ namespace CoreMidiHelpers | |||||
| // correctly when called from the message thread! | // correctly when called from the message thread! | ||||
| jassert (MessageManager::getInstance()->isThisTheMessageThread()); | jassert (MessageManager::getInstance()->isThisTheMessageThread()); | ||||
| CFStringRef name = getGlobalMidiClientName().toCFString(); | |||||
| CHECK_ERROR (MIDIClientCreate (name, &globalSystemChangeCallback, nullptr, &globalMidiClient)); | |||||
| CFRelease (name); | |||||
| CoreMidiHelpers::ScopedCFString name; | |||||
| name.cfString = getGlobalMidiClientName().toCFString(); | |||||
| CHECK_ERROR (MIDIClientCreate (name.cfString, &globalSystemChangeCallback, nullptr, &globalMidiClient)); | |||||
| } | } | ||||
| return globalMidiClient; | return globalMidiClient; | ||||
| @@ -220,12 +228,12 @@ namespace CoreMidiHelpers | |||||
| class MidiPortAndEndpoint | class MidiPortAndEndpoint | ||||
| { | { | ||||
| public: | public: | ||||
| MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) | |||||
| MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) noexcept | |||||
| : port (p), endPoint (ep) | : port (p), endPoint (ep) | ||||
| { | { | ||||
| } | } | ||||
| ~MidiPortAndEndpoint() | |||||
| ~MidiPortAndEndpoint() noexcept | |||||
| { | { | ||||
| if (port != 0) | if (port != 0) | ||||
| MIDIPortDispose (port); | MIDIPortDispose (port); | ||||
| @@ -234,7 +242,7 @@ namespace CoreMidiHelpers | |||||
| MIDIEndpointDispose (endPoint); | MIDIEndpointDispose (endPoint); | ||||
| } | } | ||||
| void send (const MIDIPacketList* const packets) | |||||
| void send (const MIDIPacketList* const packets) noexcept | |||||
| { | { | ||||
| if (port != 0) | if (port != 0) | ||||
| MIDISend (port, endPoint, packets); | MIDISend (port, endPoint, packets); | ||||
| @@ -302,7 +310,7 @@ namespace CoreMidiHelpers | |||||
| static void midiInputProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* /*srcConnRefCon*/) | static void midiInputProc (const MIDIPacketList* pktlist, void* readProcRefCon, void* /*srcConnRefCon*/) | ||||
| { | { | ||||
| static_cast <MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist); | |||||
| static_cast<MidiPortAndCallback*> (readProcRefCon)->handlePackets (pktlist); | |||||
| } | } | ||||
| } | } | ||||
| @@ -318,19 +326,18 @@ MidiOutput* MidiOutput::openDevice (int index) | |||||
| { | { | ||||
| MIDIEndpointRef endPoint = MIDIGetDestination ((ItemCount) index); | MIDIEndpointRef endPoint = MIDIGetDestination ((ItemCount) index); | ||||
| CFStringRef pname; | |||||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) | |||||
| CoreMidiHelpers::ScopedCFString pname; | |||||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname.cfString))) | |||||
| { | { | ||||
| MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | ||||
| MIDIPortRef port; | MIDIPortRef port; | ||||
| if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname, &port))) | |||||
| if (client != 0 && CHECK_ERROR (MIDIOutputPortCreate (client, pname.cfString, &port))) | |||||
| { | { | ||||
| mo = new MidiOutput(); | mo = new MidiOutput(); | ||||
| mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); | mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); | ||||
| } | } | ||||
| CFRelease (pname); | |||||
| } | } | ||||
| } | } | ||||
| @@ -339,20 +346,20 @@ MidiOutput* MidiOutput::openDevice (int index) | |||||
| MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | ||||
| { | { | ||||
| MidiOutput* mo = nullptr; | |||||
| MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | ||||
| MIDIEndpointRef endPoint; | MIDIEndpointRef endPoint; | ||||
| CFStringRef name = deviceName.toCFString(); | |||||
| if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name, &endPoint))) | |||||
| CoreMidiHelpers::ScopedCFString name; | |||||
| name.cfString = deviceName.toCFString(); | |||||
| if (client != 0 && CHECK_ERROR (MIDISourceCreate (client, name.cfString, &endPoint))) | |||||
| { | { | ||||
| mo = new MidiOutput(); | |||||
| MidiOutput* mo = new MidiOutput(); | |||||
| mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); | mo->internal = new CoreMidiHelpers::MidiPortAndEndpoint (0, endPoint); | ||||
| return mo; | |||||
| } | } | ||||
| CFRelease (name); | |||||
| return mo; | |||||
| return nullptr; | |||||
| } | } | ||||
| MidiOutput::~MidiOutput() | MidiOutput::~MidiOutput() | ||||
| @@ -370,7 +377,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||||
| const MIDITimeStamp timeStamp = AudioGetCurrentHostTime(); | const MIDITimeStamp timeStamp = AudioGetCurrentHostTime(); | ||||
| #endif | #endif | ||||
| HeapBlock <MIDIPacketList> allocatedPackets; | |||||
| HeapBlock<MIDIPacketList> allocatedPackets; | |||||
| MIDIPacketList stackPacket; | MIDIPacketList stackPacket; | ||||
| MIDIPacketList* packetToSend = &stackPacket; | MIDIPacketList* packetToSend = &stackPacket; | ||||
| const size_t dataSize = (size_t) message.getRawDataSize(); | const size_t dataSize = (size_t) message.getRawDataSize(); | ||||
| @@ -436,16 +443,16 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) | |||||
| { | { | ||||
| if (MIDIEndpointRef endPoint = MIDIGetSource ((ItemCount) index)) | if (MIDIEndpointRef endPoint = MIDIGetSource ((ItemCount) index)) | ||||
| { | { | ||||
| CFStringRef name; | |||||
| ScopedCFString name; | |||||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name))) | |||||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name.cfString))) | |||||
| { | { | ||||
| if (MIDIClientRef client = getGlobalMidiClient()) | if (MIDIClientRef client = getGlobalMidiClient()) | ||||
| { | { | ||||
| MIDIPortRef port; | MIDIPortRef port; | ||||
| ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||||
| ScopedPointer<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||||
| if (CHECK_ERROR (MIDIInputPortCreate (client, name, midiInputProc, mpc, &port))) | |||||
| if (CHECK_ERROR (MIDIInputPortCreate (client, name.cfString, midiInputProc, mpc, &port))) | |||||
| { | { | ||||
| if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, nullptr))) | if (CHECK_ERROR (MIDIPortConnectSource (port, endPoint, nullptr))) | ||||
| { | { | ||||
| @@ -465,8 +472,6 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| CFRelease (name); | |||||
| } | } | ||||
| } | } | ||||
| @@ -482,13 +487,14 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba | |||||
| if (MIDIClientRef client = getGlobalMidiClient()) | if (MIDIClientRef client = getGlobalMidiClient()) | ||||
| { | { | ||||
| ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||||
| ScopedPointer<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||||
| mpc->active = false; | mpc->active = false; | ||||
| MIDIEndpointRef endPoint; | MIDIEndpointRef endPoint; | ||||
| CFStringRef name = deviceName.toCFString(); | |||||
| ScopedCFString name; | |||||
| name.cfString = deviceName.toCFString(); | |||||
| if (CHECK_ERROR (MIDIDestinationCreate (client, name, midiInputProc, mpc, &endPoint))) | |||||
| if (CHECK_ERROR (MIDIDestinationCreate (client, name.cfString, midiInputProc, mpc, &endPoint))) | |||||
| { | { | ||||
| mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint); | mpc->portAndEndpoint = new MidiPortAndEndpoint (0, endPoint); | ||||
| @@ -499,8 +505,6 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba | |||||
| const ScopedLock sl (callbackLock); | const ScopedLock sl (callbackLock); | ||||
| activeCallbacks.add (mpc.release()); | activeCallbacks.add (mpc.release()); | ||||
| } | } | ||||
| CFRelease (name); | |||||
| } | } | ||||
| return mi; | return mi; | ||||
| @@ -341,10 +341,10 @@ namespace AiffFileHelpers | |||||
| out.writeByte ((char) labelLength + 1); | out.writeByte ((char) labelLength + 1); | ||||
| out.write (label.toUTF8(), labelLength); | out.write (label.toUTF8(), labelLength); | ||||
| out.writeByte (0); | out.writeByte (0); | ||||
| } | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| if ((out.getDataSize() & 1) != 0) | |||||
| out.writeByte (0); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1267,8 +1267,8 @@ private: | |||||
| class MemoryMappedWavReader : public MemoryMappedAudioFormatReader | class MemoryMappedWavReader : public MemoryMappedAudioFormatReader | ||||
| { | { | ||||
| public: | public: | ||||
| MemoryMappedWavReader (const File& file, const WavAudioFormatReader& reader) | |||||
| : MemoryMappedAudioFormatReader (file, reader, reader.dataChunkStart, | |||||
| MemoryMappedWavReader (const File& wavFile, const WavAudioFormatReader& reader) | |||||
| : MemoryMappedAudioFormatReader (wavFile, reader, reader.dataChunkStart, | |||||
| reader.dataLength, reader.bytesPerFrame) | reader.dataLength, reader.bytesPerFrame) | ||||
| { | { | ||||
| } | } | ||||
| @@ -163,7 +163,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| HeapBlock<int*> chans ((size_t) numTargetChannels); | |||||
| HeapBlock<int*> chans ((size_t) numTargetChannels + 1); | |||||
| readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); | readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); | ||||
| } | } | ||||
| @@ -318,6 +318,8 @@ namespace | |||||
| static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) noexcept | static void translateJuceToXMouseWheelModifiers (const MouseEvent& e, const float increment, XEvent& ev) noexcept | ||||
| { | { | ||||
| ignoreUnused (e); | |||||
| if (increment < 0) | if (increment < 0) | ||||
| { | { | ||||
| ev.xbutton.button = Button5; | ev.xbutton.button = Button5; | ||||
| @@ -1633,7 +1635,7 @@ public: | |||||
| void* data = nullptr; | void* data = nullptr; | ||||
| const size_t bytes = (size_t) dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); | const size_t bytes = (size_t) dispatch (effGetChunk, isPreset ? 1 : 0, 0, &data, 0.0f); | ||||
| if (data != nullptr && bytes <= maxSizeMB * 1024 * 1024) | |||||
| if (data != nullptr && bytes <= (size_t) maxSizeMB * 1024 * 1024) | |||||
| { | { | ||||
| mb.setSize (bytes); | mb.setSize (bytes); | ||||
| mb.copyFrom (data, 0, bytes); | mb.copyFrom (data, 0, bytes); | ||||
| @@ -29,7 +29,7 @@ | |||||
| struct NamedValueSet::NamedValue | struct NamedValueSet::NamedValue | ||||
| { | { | ||||
| NamedValue() noexcept {} | NamedValue() noexcept {} | ||||
| NamedValue (Identifier n, const var& v) : name (n), value (v) {} | |||||
| NamedValue (const Identifier& n, const var& v) : name (n), value (v) {} | |||||
| NamedValue (const NamedValue& other) : name (other.name), value (other.value) {} | NamedValue (const NamedValue& other) : name (other.name), value (other.value) {} | ||||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
| @@ -39,7 +39,9 @@ struct NamedValueSet::NamedValue | |||||
| { | { | ||||
| } | } | ||||
| NamedValue (Identifier n, var&& v) : name (n), value (static_cast<var&&> (v)) | |||||
| NamedValue (Identifier&& n, var&& v) | |||||
| : name (static_cast<Identifier&&> (n)), | |||||
| value (static_cast<var&&> (v)) | |||||
| { | { | ||||
| } | } | ||||
| @@ -138,7 +140,7 @@ var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept | |||||
| } | } | ||||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
| bool NamedValueSet::set (Identifier name, var&& newValue) | |||||
| bool NamedValueSet::set (const Identifier& name, var&& newValue) | |||||
| { | { | ||||
| if (var* const v = getVarPointer (name)) | if (var* const v = getVarPointer (name)) | ||||
| { | { | ||||
| @@ -154,7 +156,7 @@ bool NamedValueSet::set (Identifier name, var&& newValue) | |||||
| } | } | ||||
| #endif | #endif | ||||
| bool NamedValueSet::set (Identifier name, const var& newValue) | |||||
| bool NamedValueSet::set (const Identifier& name, const var& newValue) | |||||
| { | { | ||||
| if (var* const v = getVarPointer (name)) | if (var* const v = getVarPointer (name)) | ||||
| { | { | ||||
| @@ -78,14 +78,14 @@ public: | |||||
| @returns true if a value was changed or added; false if the | @returns true if a value was changed or added; false if the | ||||
| value was already set the value passed-in. | value was already set the value passed-in. | ||||
| */ | */ | ||||
| bool set (Identifier name, const var& newValue); | |||||
| bool set (const Identifier& name, const var& newValue); | |||||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
| /** Changes or adds a named value. | /** Changes or adds a named value. | ||||
| @returns true if a value was changed or added; false if the | @returns true if a value was changed or added; false if the | ||||
| value was already set the value passed-in. | value was already set the value passed-in. | ||||
| */ | */ | ||||
| bool set (Identifier name, var&& newValue); | |||||
| bool set (const Identifier& name, var&& newValue); | |||||
| #endif | #endif | ||||
| /** Returns true if the set contains an item with the specified name. */ | /** Returns true if the set contains an item with the specified name. */ | ||||
| @@ -576,7 +576,7 @@ var var::clone() const noexcept | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| const var& var::operator[] (Identifier propertyName) const | |||||
| const var& var::operator[] (const Identifier& propertyName) const | |||||
| { | { | ||||
| if (DynamicObject* const o = getDynamicObject()) | if (DynamicObject* const o = getDynamicObject()) | ||||
| return o->getProperty (propertyName); | return o->getProperty (propertyName); | ||||
| @@ -589,7 +589,7 @@ const var& var::operator[] (const char* const propertyName) const | |||||
| return operator[] (Identifier (propertyName)); | return operator[] (Identifier (propertyName)); | ||||
| } | } | ||||
| var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const | |||||
| var var::getProperty (const Identifier& propertyName, const var& defaultReturnValue) const | |||||
| { | { | ||||
| if (DynamicObject* const o = getDynamicObject()) | if (DynamicObject* const o = getDynamicObject()) | ||||
| return o->getProperties().getWithDefault (propertyName, defaultReturnValue); | return o->getProperties().getWithDefault (propertyName, defaultReturnValue); | ||||
| @@ -602,7 +602,7 @@ var::NativeFunction var::getNativeFunction() const | |||||
| return isMethod() ? value.methodValue : nullptr; | return isMethod() ? value.methodValue : nullptr; | ||||
| } | } | ||||
| var var::invoke (Identifier method, const var* arguments, int numArguments) const | |||||
| var var::invoke (const Identifier& method, const var* arguments, int numArguments) const | |||||
| { | { | ||||
| if (DynamicObject* const o = getDynamicObject()) | if (DynamicObject* const o = getDynamicObject()) | ||||
| return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments)); | return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments)); | ||||
| @@ -610,35 +610,35 @@ var var::invoke (Identifier method, const var* arguments, int numArguments) cons | |||||
| return var(); | return var(); | ||||
| } | } | ||||
| var var::call (const Identifier method) const | |||||
| var var::call (const Identifier& method) const | |||||
| { | { | ||||
| return invoke (method, nullptr, 0); | return invoke (method, nullptr, 0); | ||||
| } | } | ||||
| var var::call (const Identifier method, const var& arg1) const | |||||
| var var::call (const Identifier& method, const var& arg1) const | |||||
| { | { | ||||
| return invoke (method, &arg1, 1); | return invoke (method, &arg1, 1); | ||||
| } | } | ||||
| var var::call (const Identifier method, const var& arg1, const var& arg2) const | |||||
| var var::call (const Identifier& method, const var& arg1, const var& arg2) const | |||||
| { | { | ||||
| var args[] = { arg1, arg2 }; | var args[] = { arg1, arg2 }; | ||||
| return invoke (method, args, 2); | return invoke (method, args, 2); | ||||
| } | } | ||||
| var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3) | |||||
| var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3) | |||||
| { | { | ||||
| var args[] = { arg1, arg2, arg3 }; | var args[] = { arg1, arg2, arg3 }; | ||||
| return invoke (method, args, 3); | return invoke (method, args, 3); | ||||
| } | } | ||||
| var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const | |||||
| var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const | |||||
| { | { | ||||
| var args[] = { arg1, arg2, arg3, arg4 }; | var args[] = { arg1, arg2, arg3, arg4 }; | ||||
| return invoke (method, args, 4); | return invoke (method, args, 4); | ||||
| } | } | ||||
| var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const | |||||
| var var::call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const | |||||
| { | { | ||||
| var args[] = { arg1, arg2, arg3, arg4, arg5 }; | var args[] = { arg1, arg2, arg3, arg4, arg5 }; | ||||
| return invoke (method, args, 5); | return invoke (method, args, 5); | ||||
| @@ -62,7 +62,6 @@ public: | |||||
| }; | }; | ||||
| typedef var (*NativeFunction) (const NativeFunctionArgs&); | typedef var (*NativeFunction) (const NativeFunctionArgs&); | ||||
| typedef Identifier identifier; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates a void variant. */ | /** Creates a void variant. */ | ||||
| @@ -242,27 +241,27 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** If this variant is an object, this returns one of its properties. */ | /** If this variant is an object, this returns one of its properties. */ | ||||
| const var& operator[] (Identifier propertyName) const; | |||||
| const var& operator[] (const Identifier& propertyName) const; | |||||
| /** If this variant is an object, this returns one of its properties. */ | /** If this variant is an object, this returns one of its properties. */ | ||||
| const var& operator[] (const char* propertyName) const; | const var& operator[] (const char* propertyName) const; | ||||
| /** If this variant is an object, this returns one of its properties, or a default | /** If this variant is an object, this returns one of its properties, or a default | ||||
| fallback value if the property is not set. */ | fallback value if the property is not set. */ | ||||
| var getProperty (Identifier propertyName, const var& defaultReturnValue) const; | |||||
| var getProperty (const Identifier& propertyName, const var& defaultReturnValue) const; | |||||
| /** Invokes a named method call with no arguments. */ | /** Invokes a named method call with no arguments. */ | ||||
| var call (Identifier method) const; | |||||
| var call (const Identifier& method) const; | |||||
| /** Invokes a named method call with one argument. */ | /** Invokes a named method call with one argument. */ | ||||
| var call (Identifier method, const var& arg1) const; | |||||
| var call (const Identifier& method, const var& arg1) const; | |||||
| /** Invokes a named method call with 2 arguments. */ | /** Invokes a named method call with 2 arguments. */ | ||||
| var call (Identifier method, const var& arg1, const var& arg2) const; | |||||
| var call (const Identifier& method, const var& arg1, const var& arg2) const; | |||||
| /** Invokes a named method call with 3 arguments. */ | /** Invokes a named method call with 3 arguments. */ | ||||
| var call (Identifier method, const var& arg1, const var& arg2, const var& arg3); | |||||
| var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3); | |||||
| /** Invokes a named method call with 4 arguments. */ | /** Invokes a named method call with 4 arguments. */ | ||||
| var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; | |||||
| var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; | |||||
| /** Invokes a named method call with 5 arguments. */ | /** Invokes a named method call with 5 arguments. */ | ||||
| var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; | |||||
| var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; | |||||
| /** Invokes a named method call with a list of arguments. */ | /** Invokes a named method call with a list of arguments. */ | ||||
| var invoke (Identifier method, const var* arguments, int numArguments) const; | |||||
| var invoke (const Identifier& method, const var* arguments, int numArguments) const; | |||||
| /** If this object is a method, this returns the function pointer. */ | /** If this object is a method, this returns the function pointer. */ | ||||
| NativeFunction getNativeFunction() const; | NativeFunction getNativeFunction() const; | ||||
| @@ -916,6 +916,11 @@ public: | |||||
| const File temp (File::getSpecialLocation (File::tempDirectory)); | const File temp (File::getSpecialLocation (File::tempDirectory)); | ||||
| expect (! File::nonexistent.exists()); | expect (! File::nonexistent.exists()); | ||||
| expect (! File::nonexistent.existsAsFile()); | |||||
| expect (! File::nonexistent.isDirectory()); | |||||
| #if ! JUCE_WINDOWS | |||||
| expect (File("/").isDirectory()); | |||||
| #endif | |||||
| expect (home.isDirectory()); | expect (home.isDirectory()); | ||||
| expect (home.exists()); | expect (home.exists()); | ||||
| expect (! home.existsAsFile()); | expect (! home.existsAsFile()); | ||||
| @@ -102,7 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); } | static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); } | ||||
| static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); } | static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); } | ||||
| static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; } | static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; } | ||||
| static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); } | |||||
| static var* getPropertyPointer (DynamicObject* o, const Identifier& i) { return o->getProperties().getVarPointer (i); } | |||||
| //============================================================================== | //============================================================================== | ||||
| struct CodeLocation | struct CodeLocation | ||||
| @@ -136,7 +136,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| ReferenceCountedObjectPtr<RootObject> root; | ReferenceCountedObjectPtr<RootObject> root; | ||||
| DynamicObject::Ptr scope; | DynamicObject::Ptr scope; | ||||
| var findFunctionCall (const CodeLocation& location, const var& targetObject, Identifier functionName) const | |||||
| var findFunctionCall (const CodeLocation& location, const var& targetObject, const Identifier& functionName) const | |||||
| { | { | ||||
| if (DynamicObject* o = targetObject.getDynamicObject()) | if (DynamicObject* o = targetObject.getDynamicObject()) | ||||
| { | { | ||||
| @@ -170,7 +170,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| return var(); | return var(); | ||||
| } | } | ||||
| var* findRootClassProperty (Identifier className, Identifier propName) const | |||||
| var* findRootClassProperty (const Identifier& className, const Identifier& propName) const | |||||
| { | { | ||||
| if (DynamicObject* cls = root->getProperty (className).getDynamicObject()) | if (DynamicObject* cls = root->getProperty (className).getDynamicObject()) | ||||
| return getPropertyPointer (cls, propName); | return getPropertyPointer (cls, propName); | ||||
| @@ -178,7 +178,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| var findSymbolInParentScopes (Identifier name) const | |||||
| var findSymbolInParentScopes (const Identifier& name) const | |||||
| { | { | ||||
| if (const var* v = getPropertyPointer (scope, name)) | if (const var* v = getPropertyPointer (scope, name)) | ||||
| return *v; | return *v; | ||||
| @@ -187,7 +187,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| : var::undefined(); | : var::undefined(); | ||||
| } | } | ||||
| bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const | |||||
| bool findAndInvokeMethod (const Identifier& function, const var::NativeFunctionArgs& args, var& result) const | |||||
| { | { | ||||
| DynamicObject* target = args.thisObject.getDynamicObject(); | DynamicObject* target = args.thisObject.getDynamicObject(); | ||||
| @@ -352,7 +352,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| struct UnqualifiedName : public Expression | struct UnqualifiedName : public Expression | ||||
| { | { | ||||
| UnqualifiedName (const CodeLocation& l, Identifier n) noexcept : Expression (l), name (n) {} | |||||
| UnqualifiedName (const CodeLocation& l, const Identifier& n) noexcept : Expression (l), name (n) {} | |||||
| var getResult (const Scope& s) const override { return s.findSymbolInParentScopes (name); } | var getResult (const Scope& s) const override { return s.findSymbolInParentScopes (name); } | ||||
| @@ -369,7 +369,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||||
| struct DotOperator : public Expression | struct DotOperator : public Expression | ||||
| { | { | ||||
| DotOperator (const CodeLocation& l, ExpPtr& p, Identifier c) noexcept : Expression (l), parent (p), child (c) {} | |||||
| DotOperator (const CodeLocation& l, ExpPtr& p, const Identifier& c) noexcept : Expression (l), parent (p), child (c) {} | |||||
| var getResult (const Scope& s) const override | var getResult (const Scope& s) const override | ||||
| { | { | ||||
| @@ -1670,7 +1670,7 @@ JavascriptEngine::~JavascriptEngine() {} | |||||
| void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; } | void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; } | ||||
| void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object) | |||||
| void JavascriptEngine::registerNativeObject (const Identifier& name, DynamicObject* object) | |||||
| { | { | ||||
| root->setProperty (name, object); | root->setProperty (name, object); | ||||
| } | } | ||||
| @@ -1706,7 +1706,7 @@ var JavascriptEngine::evaluate (const String& code, Result* result) | |||||
| return var::undefined(); | return var::undefined(); | ||||
| } | } | ||||
| var JavascriptEngine::callFunction (Identifier function, const var::NativeFunctionArgs& args, Result* result) | |||||
| var JavascriptEngine::callFunction (const Identifier& function, const var::NativeFunctionArgs& args, Result* result) | |||||
| { | { | ||||
| var returnVal (var::undefined()); | var returnVal (var::undefined()); | ||||
| @@ -78,7 +78,7 @@ public: | |||||
| The function arguments are passed in the same format as used by native | The function arguments are passed in the same format as used by native | ||||
| methods in the var class. | methods in the var class. | ||||
| */ | */ | ||||
| var callFunction (Identifier function, | |||||
| var callFunction (const Identifier& function, | |||||
| const var::NativeFunctionArgs& args, | const var::NativeFunctionArgs& args, | ||||
| Result* errorMessage = nullptr); | Result* errorMessage = nullptr); | ||||
| @@ -87,7 +87,7 @@ public: | |||||
| engine until the engine is deleted. The name must be a simple JS identifier, | engine until the engine is deleted. The name must be a simple JS identifier, | ||||
| without any dots. | without any dots. | ||||
| */ | */ | ||||
| void registerNativeObject (Identifier objectName, DynamicObject* object); | |||||
| void registerNativeObject (const Identifier& objectName, DynamicObject* object); | |||||
| /** This value indicates how long a call to one of the evaluate methods is permitted | /** This value indicates how long a call to one of the evaluate methods is permitted | ||||
| to run before timing-out and failing. | to run before timing-out and failing. | ||||
| @@ -45,6 +45,16 @@ struct ContainerDeletePolicy | |||||
| { | { | ||||
| static void destroy (ObjectType* object) | static void destroy (ObjectType* object) | ||||
| { | { | ||||
| // If the line below triggers a compiler error, it means that you are using | |||||
| // an incomplete type for ObjectType (for example, a type that is declared | |||||
| // but not defined). This is a problem because then the following delete is | |||||
| // undefined behaviour. The purpose of the sizeof is to capture this situation. | |||||
| // If this was caused by a ScopedPointer to a forward-declared type, move the | |||||
| // implementation of all methods trying to use the ScopedPointer (e.g. the destructor | |||||
| // of the class owning it) into cpp files where they can see to the definition | |||||
| // of ObjectType. This should fix the error. | |||||
| ignoreUnused (sizeof (ObjectType)); | |||||
| delete object; | delete object; | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -50,7 +50,7 @@ inline void deleteAndZero (Type& pointer) { delete poi | |||||
| a specific number of bytes, | a specific number of bytes, | ||||
| */ | */ | ||||
| template <typename Type, typename IntegerType> | template <typename Type, typename IntegerType> | ||||
| inline Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept { return (Type*) (((char*) pointer) + bytes); } | |||||
| inline Type* addBytesToPointer (Type* basePointer, IntegerType bytes) noexcept { return (Type*) (((char*) basePointer) + bytes); } | |||||
| /** A handy function which returns the difference between any two pointers, in bytes. | /** A handy function which returns the difference between any two pointers, in bytes. | ||||
| The address of the second pointer is subtracted from the first, and the difference in bytes is returned. | The address of the second pointer is subtracted from the first, and the difference in bytes is returned. | ||||
| @@ -62,7 +62,7 @@ inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { r | |||||
| nullptr if the pointer is null. | nullptr if the pointer is null. | ||||
| */ | */ | ||||
| template <class Type> | template <class Type> | ||||
| inline Type* createCopyIfNotNull (const Type* pointer) { return pointer != nullptr ? new Type (*pointer) : nullptr; } | |||||
| inline Type* createCopyIfNotNull (const Type* objectToCopy) { return objectToCopy != nullptr ? new Type (*objectToCopy) : nullptr; } | |||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_MAC || JUCE_IOS || DOXYGEN | #if JUCE_MAC || JUCE_IOS || DOXYGEN | ||||
| @@ -94,13 +94,12 @@ public: | |||||
| */ | */ | ||||
| SharedResourcePointer() | SharedResourcePointer() | ||||
| { | { | ||||
| SharedObjectHolder& holder = getSharedObjectHolder(); | |||||
| const SpinLock::ScopedLockType sl (holder.lock); | |||||
| if (++(holder.refCount) == 1) | |||||
| holder.sharedInstance = new SharedObjectType(); | |||||
| initialise(); | |||||
| } | |||||
| sharedObject = holder.sharedInstance; | |||||
| SharedResourcePointer (const SharedResourcePointer&) | |||||
| { | |||||
| initialise(); | |||||
| } | } | ||||
| /** Destructor. | /** Destructor. | ||||
| @@ -145,7 +144,22 @@ private: | |||||
| SharedObjectType* sharedObject; | SharedObjectType* sharedObject; | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedResourcePointer) | |||||
| void initialise() | |||||
| { | |||||
| SharedObjectHolder& holder = getSharedObjectHolder(); | |||||
| const SpinLock::ScopedLockType sl (holder.lock); | |||||
| if (++(holder.refCount) == 1) | |||||
| holder.sharedInstance = new SharedObjectType(); | |||||
| sharedObject = holder.sharedInstance; | |||||
| } | |||||
| // There's no need to assign to a SharedResourcePointer because every | |||||
| // instance of the class is exactly the same! | |||||
| SharedResourcePointer& operator= (const SharedResourcePointer&) JUCE_DELETED_FUNCTION; | |||||
| JUCE_LEAK_DETECTOR (SharedResourcePointer) | |||||
| }; | }; | ||||
| @@ -265,8 +265,8 @@ bool File::isDirectory() const | |||||
| { | { | ||||
| juce_statStruct info; | juce_statStruct info; | ||||
| return fullPath.isEmpty() | |||||
| || (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0)); | |||||
| return fullPath.isNotEmpty() | |||||
| && (juce_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0)); | |||||
| } | } | ||||
| bool File::exists() const | bool File::exists() const | ||||
| @@ -248,6 +248,9 @@ public: | |||||
| /** Attempts to open a stream that can read from this URL. | /** Attempts to open a stream that can read from this URL. | ||||
| Note that on some platforms (Android, for example) it's not permitted to do any network | |||||
| action from the message thread, so you must only call it from a background thread. | |||||
| @param usePostCommand if true, it will try to do use a http 'POST' to pass | @param usePostCommand if true, it will try to do use a http 'POST' to pass | ||||
| the parameters, otherwise it'll encode them into the | the parameters, otherwise it'll encode them into the | ||||
| URL and do a 'GET'. | URL and do a 'GET'. | ||||
| @@ -287,6 +290,9 @@ public: | |||||
| If it succeeds, this will return true and append the data it read onto the end | If it succeeds, this will return true and append the data it read onto the end | ||||
| of the memory block. | of the memory block. | ||||
| Note that on some platforms (Android, for example) it's not permitted to do any network | |||||
| action from the message thread, so you must only call it from a background thread. | |||||
| @param destData the memory block to append the new data to | @param destData the memory block to append the new data to | ||||
| @param usePostCommand whether to use a POST command to get the data (uses | @param usePostCommand whether to use a POST command to get the data (uses | ||||
| a GET command if this is false) | a GET command if this is false) | ||||
| @@ -302,6 +308,9 @@ public: | |||||
| operation that fails and one that returns an empty string, you'll need to use | operation that fails and one that returns an empty string, you'll need to use | ||||
| a different method, such as readEntireBinaryStream(). | a different method, such as readEntireBinaryStream(). | ||||
| Note that on some platforms (Android, for example) it's not permitted to do any network | |||||
| action from the message thread, so you must only call it from a background thread. | |||||
| @param usePostCommand whether to use a POST command to get the data (uses | @param usePostCommand whether to use a POST command to get the data (uses | ||||
| a GET command if this is false) | a GET command if this is false) | ||||
| @see readEntireBinaryStream, readEntireXmlStream | @see readEntireBinaryStream, readEntireXmlStream | ||||
| @@ -316,6 +325,9 @@ public: | |||||
| When it returns a valid XmlElement object, the caller is responsibile for deleting | When it returns a valid XmlElement object, the caller is responsibile for deleting | ||||
| this object when no longer needed. | this object when no longer needed. | ||||
| Note that on some platforms (Android, for example) it's not permitted to do any network | |||||
| action from the message thread, so you must only call it from a background thread. | |||||
| @param usePostCommand whether to use a POST command to get the data (uses | @param usePostCommand whether to use a POST command to get the data (uses | ||||
| a GET command if this is false) | a GET command if this is false) | ||||
| @@ -31,7 +31,17 @@ Identifier::~Identifier() noexcept {} | |||||
| Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {} | Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {} | ||||
| Identifier& Identifier::operator= (const Identifier other) noexcept | |||||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| Identifier::Identifier (Identifier&& other) noexcept : name (static_cast<String&&> (other.name)) {} | |||||
| Identifier& Identifier::operator= (Identifier&& other) noexcept | |||||
| { | |||||
| name = static_cast<String&&> (other.name); | |||||
| return *this; | |||||
| } | |||||
| #endif | |||||
| Identifier& Identifier::operator= (const Identifier& other) noexcept | |||||
| { | { | ||||
| name = other.name; | name = other.name; | ||||
| return *this; | return *this; | ||||
| @@ -68,16 +68,24 @@ public: | |||||
| Identifier (const Identifier& other) noexcept; | Identifier (const Identifier& other) noexcept; | ||||
| /** Creates a copy of another identifier. */ | /** Creates a copy of another identifier. */ | ||||
| Identifier& operator= (const Identifier other) noexcept; | |||||
| Identifier& operator= (const Identifier& other) noexcept; | |||||
| #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| /** Creates a copy of another identifier. */ | |||||
| Identifier (Identifier&& other) noexcept; | |||||
| /** Creates a copy of another identifier. */ | |||||
| Identifier& operator= (Identifier&& other) noexcept; | |||||
| #endif | |||||
| /** Destructor */ | /** Destructor */ | ||||
| ~Identifier() noexcept; | ~Identifier() noexcept; | ||||
| /** Compares two identifiers. This is a very fast operation. */ | /** Compares two identifiers. This is a very fast operation. */ | ||||
| inline bool operator== (Identifier other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); } | |||||
| inline bool operator== (const Identifier& other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); } | |||||
| /** Compares two identifiers. This is a very fast operation. */ | /** Compares two identifiers. This is a very fast operation. */ | ||||
| inline bool operator!= (Identifier other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); } | |||||
| inline bool operator!= (const Identifier& other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); } | |||||
| /** Compares the identifier with a string. */ | /** Compares the identifier with a string. */ | ||||
| inline bool operator== (StringRef other) const noexcept { return name == other; } | inline bool operator== (StringRef other) const noexcept { return name == other; } | ||||
| @@ -89,12 +89,12 @@ public: | |||||
| */ | */ | ||||
| String (const char* text, size_t maxChars); | String (const char* text, size_t maxChars); | ||||
| /** Creates a string from a whcar_t character string. | |||||
| /** Creates a string from a wchar_t character string. | |||||
| Depending on the platform, this may be treated as either UTF-32 or UTF-16. | Depending on the platform, this may be treated as either UTF-32 or UTF-16. | ||||
| */ | */ | ||||
| String (const wchar_t* text); | String (const wchar_t* text); | ||||
| /** Creates a string from a whcar_t character string. | |||||
| /** Creates a string from a wchar_t character string. | |||||
| Depending on the platform, this may be treated as either UTF-32 or UTF-16. | Depending on the platform, this may be treated as either UTF-32 or UTF-16. | ||||
| */ | */ | ||||
| String (const wchar_t* text, size_t maxChars); | String (const wchar_t* text, size_t maxChars); | ||||
| @@ -27,7 +27,7 @@ class ValueTree::SharedObject : public ReferenceCountedObject | |||||
| public: | public: | ||||
| typedef ReferenceCountedObjectPtr<SharedObject> Ptr; | typedef ReferenceCountedObjectPtr<SharedObject> Ptr; | ||||
| explicit SharedObject (Identifier t) noexcept | |||||
| explicit SharedObject (const Identifier& t) noexcept | |||||
| : type (t), parent (nullptr) | : type (t), parent (nullptr) | ||||
| { | { | ||||
| } | } | ||||
| @@ -126,7 +126,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| void sendPropertyChangeMessage (const Identifier property) | |||||
| void sendPropertyChangeMessage (const Identifier& property) | |||||
| { | { | ||||
| ValueTree tree (this); | ValueTree tree (this); | ||||
| @@ -169,7 +169,7 @@ public: | |||||
| callListeners (&ValueTree::Listener::valueTreeParentChanged, tree); | callListeners (&ValueTree::Listener::valueTreeParentChanged, tree); | ||||
| } | } | ||||
| void setProperty (const Identifier name, const var& newValue, UndoManager* const undoManager) | |||||
| void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager) | |||||
| { | { | ||||
| if (undoManager == nullptr) | if (undoManager == nullptr) | ||||
| { | { | ||||
| @@ -190,12 +190,12 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| bool hasProperty (const Identifier name) const noexcept | |||||
| bool hasProperty (const Identifier& name) const noexcept | |||||
| { | { | ||||
| return properties.contains (name); | return properties.contains (name); | ||||
| } | } | ||||
| void removeProperty (const Identifier name, UndoManager* const undoManager) | |||||
| void removeProperty (const Identifier& name, UndoManager* const undoManager) | |||||
| { | { | ||||
| if (undoManager == nullptr) | if (undoManager == nullptr) | ||||
| { | { | ||||
| @@ -238,7 +238,7 @@ public: | |||||
| setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager); | setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager); | ||||
| } | } | ||||
| ValueTree getChildWithName (const Identifier typeToMatch) const | |||||
| ValueTree getChildWithName (const Identifier& typeToMatch) const | |||||
| { | { | ||||
| for (int i = 0; i < children.size(); ++i) | for (int i = 0; i < children.size(); ++i) | ||||
| { | { | ||||
| @@ -250,7 +250,7 @@ public: | |||||
| return ValueTree(); | return ValueTree(); | ||||
| } | } | ||||
| ValueTree getOrCreateChildWithName (const Identifier typeToMatch, UndoManager* undoManager) | |||||
| ValueTree getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager) | |||||
| { | { | ||||
| for (int i = 0; i < children.size(); ++i) | for (int i = 0; i < children.size(); ++i) | ||||
| { | { | ||||
| @@ -265,7 +265,7 @@ public: | |||||
| } | } | ||||
| ValueTree getChildWithProperty (const Identifier propertyName, const var& propertyValue) const | |||||
| ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const | |||||
| { | { | ||||
| for (int i = 0; i < children.size(); ++i) | for (int i = 0; i < children.size(); ++i) | ||||
| { | { | ||||
| @@ -458,7 +458,7 @@ public: | |||||
| class SetPropertyAction : public UndoableAction | class SetPropertyAction : public UndoableAction | ||||
| { | { | ||||
| public: | public: | ||||
| SetPropertyAction (SharedObject* const so, const Identifier propertyName, | |||||
| SetPropertyAction (SharedObject* const so, const Identifier& propertyName, | |||||
| const var& newVal, const var& oldVal, bool isAdding, bool isDeleting) | const var& newVal, const var& oldVal, bool isAdding, bool isDeleting) | ||||
| : target (so), name (propertyName), newValue (newVal), oldValue (oldVal), | : target (so), name (propertyName), newValue (newVal), oldValue (oldVal), | ||||
| isAddingNewProperty (isAdding), isDeletingProperty (isDeleting) | isAddingNewProperty (isAdding), isDeletingProperty (isDeleting) | ||||
| @@ -629,7 +629,7 @@ ValueTree::ValueTree() noexcept | |||||
| const ValueTree ValueTree::invalid; | const ValueTree ValueTree::invalid; | ||||
| ValueTree::ValueTree (Identifier type) : object (new ValueTree::SharedObject (type)) | |||||
| ValueTree::ValueTree (const Identifier& type) : object (new ValueTree::SharedObject (type)) | |||||
| { | { | ||||
| jassert (type.toString().isNotEmpty()); // All objects must be given a sensible type name! | jassert (type.toString().isNotEmpty()); // All objects must be given a sensible type name! | ||||
| } | } | ||||
| @@ -702,7 +702,7 @@ ValueTree ValueTree::createCopy() const | |||||
| return ValueTree (createCopyIfNotNull (object.get())); | return ValueTree (createCopyIfNotNull (object.get())); | ||||
| } | } | ||||
| bool ValueTree::hasType (const Identifier typeName) const | |||||
| bool ValueTree::hasType (const Identifier& typeName) const | |||||
| { | { | ||||
| return object != nullptr && object->type == typeName; | return object != nullptr && object->type == typeName; | ||||
| } | } | ||||
| @@ -727,24 +727,23 @@ ValueTree ValueTree::getSibling (const int delta) const | |||||
| return ValueTree (object->parent->children.getObjectPointer (index)); | return ValueTree (object->parent->children.getObjectPointer (index)); | ||||
| } | } | ||||
| const var& ValueTree::operator[] (const Identifier name) const | |||||
| const var& ValueTree::operator[] (const Identifier& name) const | |||||
| { | { | ||||
| return object == nullptr ? var::null : object->properties[name]; | return object == nullptr ? var::null : object->properties[name]; | ||||
| } | } | ||||
| const var& ValueTree::getProperty (const Identifier name) const | |||||
| const var& ValueTree::getProperty (const Identifier& name) const | |||||
| { | { | ||||
| return object == nullptr ? var::null : object->properties[name]; | return object == nullptr ? var::null : object->properties[name]; | ||||
| } | } | ||||
| var ValueTree::getProperty (const Identifier name, const var& defaultReturnValue) const | |||||
| var ValueTree::getProperty (const Identifier& name, const var& defaultReturnValue) const | |||||
| { | { | ||||
| return object == nullptr ? defaultReturnValue | return object == nullptr ? defaultReturnValue | ||||
| : object->properties.getWithDefault (name, defaultReturnValue); | : object->properties.getWithDefault (name, defaultReturnValue); | ||||
| } | } | ||||
| ValueTree& ValueTree::setProperty (const Identifier name, const var& newValue, | |||||
| UndoManager* const undoManager) | |||||
| ValueTree& ValueTree::setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager) | |||||
| { | { | ||||
| jassert (name.toString().isNotEmpty()); // Must have a valid property name! | jassert (name.toString().isNotEmpty()); // Must have a valid property name! | ||||
| jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail! | jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail! | ||||
| @@ -755,12 +754,12 @@ ValueTree& ValueTree::setProperty (const Identifier name, const var& newValue, | |||||
| return *this; | return *this; | ||||
| } | } | ||||
| bool ValueTree::hasProperty (const Identifier name) const | |||||
| bool ValueTree::hasProperty (const Identifier& name) const | |||||
| { | { | ||||
| return object != nullptr && object->hasProperty (name); | return object != nullptr && object->hasProperty (name); | ||||
| } | } | ||||
| void ValueTree::removeProperty (const Identifier name, UndoManager* const undoManager) | |||||
| void ValueTree::removeProperty (const Identifier& name, UndoManager* const undoManager) | |||||
| { | { | ||||
| if (object != nullptr) | if (object != nullptr) | ||||
| object->removeProperty (name, undoManager); | object->removeProperty (name, undoManager); | ||||
| @@ -803,7 +802,7 @@ class ValueTreePropertyValueSource : public Value::ValueSource, | |||||
| private ValueTree::Listener | private ValueTree::Listener | ||||
| { | { | ||||
| public: | public: | ||||
| ValueTreePropertyValueSource (const ValueTree& vt, const Identifier prop, UndoManager* um) | |||||
| ValueTreePropertyValueSource (const ValueTree& vt, const Identifier& prop, UndoManager* um) | |||||
| : tree (vt), property (prop), undoManager (um) | : tree (vt), property (prop), undoManager (um) | ||||
| { | { | ||||
| tree.addListener (this); | tree.addListener (this); | ||||
| @@ -836,7 +835,7 @@ private: | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreePropertyValueSource) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueTreePropertyValueSource) | ||||
| }; | }; | ||||
| Value ValueTree::getPropertyAsValue (const Identifier name, UndoManager* const undoManager) | |||||
| Value ValueTree::getPropertyAsValue (const Identifier& name, UndoManager* const undoManager) | |||||
| { | { | ||||
| return Value (new ValueTreePropertyValueSource (*this, name, undoManager)); | return Value (new ValueTreePropertyValueSource (*this, name, undoManager)); | ||||
| } | } | ||||
| @@ -853,17 +852,17 @@ ValueTree ValueTree::getChild (int index) const | |||||
| : static_cast<SharedObject*> (nullptr)); | : static_cast<SharedObject*> (nullptr)); | ||||
| } | } | ||||
| ValueTree ValueTree::getChildWithName (const Identifier type) const | |||||
| ValueTree ValueTree::getChildWithName (const Identifier& type) const | |||||
| { | { | ||||
| return object != nullptr ? object->getChildWithName (type) : ValueTree(); | return object != nullptr ? object->getChildWithName (type) : ValueTree(); | ||||
| } | } | ||||
| ValueTree ValueTree::getOrCreateChildWithName (const Identifier type, UndoManager* undoManager) | |||||
| ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager) | |||||
| { | { | ||||
| return object != nullptr ? object->getOrCreateChildWithName (type, undoManager) : ValueTree(); | return object != nullptr ? object->getOrCreateChildWithName (type, undoManager) : ValueTree(); | ||||
| } | } | ||||
| ValueTree ValueTree::getChildWithProperty (const Identifier propertyName, const var& propertyValue) const | |||||
| ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const | |||||
| { | { | ||||
| return object != nullptr ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree(); | return object != nullptr ? object->getChildWithProperty (propertyName, propertyValue) : ValueTree(); | ||||
| } | } | ||||
| @@ -945,7 +944,7 @@ void ValueTree::removeListener (Listener* listener) | |||||
| object->valueTreesWithListeners.removeValue (this); | object->valueTreesWithListeners.removeValue (this); | ||||
| } | } | ||||
| void ValueTree::sendPropertyChangeMessage (const Identifier property) | |||||
| void ValueTree::sendPropertyChangeMessage (const Identifier& property) | |||||
| { | { | ||||
| if (object != nullptr) | if (object != nullptr) | ||||
| object->sendPropertyChangeMessage (property); | object->sendPropertyChangeMessage (property); | ||||
| @@ -79,7 +79,7 @@ public: | |||||
| Like an XmlElement, each ValueTree node has a type, which you can access with | Like an XmlElement, each ValueTree node has a type, which you can access with | ||||
| getType() and hasType(). | getType() and hasType(). | ||||
| */ | */ | ||||
| explicit ValueTree (Identifier type); | |||||
| explicit ValueTree (const Identifier& type); | |||||
| /** Creates a reference to another ValueTree. */ | /** Creates a reference to another ValueTree. */ | ||||
| ValueTree (const ValueTree&); | ValueTree (const ValueTree&); | ||||
| @@ -134,7 +134,7 @@ public: | |||||
| /** Returns true if the node has this type. | /** Returns true if the node has this type. | ||||
| The comparison is case-sensitive. | The comparison is case-sensitive. | ||||
| */ | */ | ||||
| bool hasType (const Identifier typeName) const; | |||||
| bool hasType (const Identifier& typeName) const; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the value of a named property. | /** Returns the value of a named property. | ||||
| @@ -142,21 +142,21 @@ public: | |||||
| You can also use operator[] to get a property. | You can also use operator[] to get a property. | ||||
| @see var, setProperty, hasProperty | @see var, setProperty, hasProperty | ||||
| */ | */ | ||||
| const var& getProperty (const Identifier name) const; | |||||
| const var& getProperty (const Identifier& name) const; | |||||
| /** Returns the value of a named property, or a user-specified default if the property doesn't exist. | /** Returns the value of a named property, or a user-specified default if the property doesn't exist. | ||||
| If no such property has been set, this will return the value of defaultReturnValue. | If no such property has been set, this will return the value of defaultReturnValue. | ||||
| You can also use operator[] and getProperty to get a property. | You can also use operator[] and getProperty to get a property. | ||||
| @see var, getProperty, setProperty, hasProperty | @see var, getProperty, setProperty, hasProperty | ||||
| */ | */ | ||||
| var getProperty (const Identifier name, const var& defaultReturnValue) const; | |||||
| var getProperty (const Identifier& name, const var& defaultReturnValue) const; | |||||
| /** Returns the value of a named property. | /** Returns the value of a named property. | ||||
| If no such property has been set, this will return a void variant. This is the same as | If no such property has been set, this will return a void variant. This is the same as | ||||
| calling getProperty(). | calling getProperty(). | ||||
| @see getProperty | @see getProperty | ||||
| */ | */ | ||||
| const var& operator[] (const Identifier name) const; | |||||
| const var& operator[] (const Identifier& name) const; | |||||
| /** Changes a named property of the node. | /** Changes a named property of the node. | ||||
| The name identifier must not be an empty string. | The name identifier must not be an empty string. | ||||
| @@ -165,16 +165,16 @@ public: | |||||
| @see var, getProperty, removeProperty | @see var, getProperty, removeProperty | ||||
| @returns a reference to the value tree, so that you can daisy-chain calls to this method. | @returns a reference to the value tree, so that you can daisy-chain calls to this method. | ||||
| */ | */ | ||||
| ValueTree& setProperty (const Identifier name, const var& newValue, UndoManager* undoManager); | |||||
| ValueTree& setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager); | |||||
| /** Returns true if the node contains a named property. */ | /** Returns true if the node contains a named property. */ | ||||
| bool hasProperty (const Identifier name) const; | |||||
| bool hasProperty (const Identifier& name) const; | |||||
| /** Removes a property from the node. | /** Removes a property from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| so that this change can be undone. | so that this change can be undone. | ||||
| */ | */ | ||||
| void removeProperty (const Identifier name, UndoManager* undoManager); | |||||
| void removeProperty (const Identifier& name, UndoManager* undoManager); | |||||
| /** Removes all properties from the node. | /** Removes all properties from the node. | ||||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | ||||
| @@ -198,7 +198,7 @@ public: | |||||
| it needs to change the value. Attaching a Value::Listener to the value object will provide | it needs to change the value. Attaching a Value::Listener to the value object will provide | ||||
| callbacks whenever the property changes. | callbacks whenever the property changes. | ||||
| */ | */ | ||||
| Value getPropertyAsValue (const Identifier name, UndoManager* undoManager); | |||||
| Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager); | |||||
| /** Overwrites all the properties in this tree with the properties of the source tree. | /** Overwrites all the properties in this tree with the properties of the source tree. | ||||
| Any properties that already exist will be updated; and new ones will be added, and | Any properties that already exist will be updated; and new ones will be added, and | ||||
| @@ -223,7 +223,7 @@ public: | |||||
| whether a node is valid). | whether a node is valid). | ||||
| @see getOrCreateChildWithName | @see getOrCreateChildWithName | ||||
| */ | */ | ||||
| ValueTree getChildWithName (const Identifier type) const; | |||||
| ValueTree getChildWithName (const Identifier& type) const; | |||||
| /** Returns the first child node with the speficied type name, creating and adding | /** Returns the first child node with the speficied type name, creating and adding | ||||
| a child with this name if there wasn't already one there. | a child with this name if there wasn't already one there. | ||||
| @@ -232,7 +232,7 @@ public: | |||||
| the method on is itself invalid. | the method on is itself invalid. | ||||
| @see getChildWithName | @see getChildWithName | ||||
| */ | */ | ||||
| ValueTree getOrCreateChildWithName (const Identifier type, UndoManager* undoManager); | |||||
| ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager); | |||||
| /** Looks for the first child node that has the speficied property value. | /** Looks for the first child node that has the speficied property value. | ||||
| @@ -242,7 +242,7 @@ public: | |||||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | If no such node is found, it'll return an invalid node. (See isValid() to find out | ||||
| whether a node is valid). | whether a node is valid). | ||||
| */ | */ | ||||
| ValueTree getChildWithProperty (const Identifier propertyName, const var& propertyValue) const; | |||||
| ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; | |||||
| /** Adds a child to this node. | /** Adds a child to this node. | ||||
| @@ -453,7 +453,7 @@ public: | |||||
| /** Causes a property-change callback to be triggered for the specified property, | /** Causes a property-change callback to be triggered for the specified property, | ||||
| calling any listeners that are registered. | calling any listeners that are registered. | ||||
| */ | */ | ||||
| void sendPropertyChangeMessage (const Identifier property); | |||||
| void sendPropertyChangeMessage (const Identifier& property); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** This method uses a comparator object to sort the tree's children into order. | /** This method uses a comparator object to sort the tree's children into order. | ||||
| @@ -32,8 +32,8 @@ namespace | |||||
| jassert ((int) x >= -maxVal && (int) x <= maxVal | jassert ((int) x >= -maxVal && (int) x <= maxVal | ||||
| && (int) y >= -maxVal && (int) y <= maxVal | && (int) y >= -maxVal && (int) y <= maxVal | ||||
| && (int) w >= -maxVal && (int) w <= maxVal | |||||
| && (int) h >= -maxVal && (int) h <= maxVal); | |||||
| && (int) w >= 0 && (int) w <= maxVal | |||||
| && (int) h >= 0 && (int) h <= maxVal); | |||||
| #endif | #endif | ||||
| return Rectangle<Type> (x, y, w, h); | return Rectangle<Type> (x, y, w, h); | ||||
| @@ -427,6 +427,8 @@ void Graphics::drawRect (const Rectangle<int>& r, int lineThickness) const | |||||
| void Graphics::drawRect (Rectangle<float> r, const float lineThickness) const | void Graphics::drawRect (Rectangle<float> r, const float lineThickness) const | ||||
| { | { | ||||
| jassert (r.getWidth() >= 0.0f && r.getHeight() >= 0.0f); | |||||
| RectangleList<float> rects; | RectangleList<float> rects; | ||||
| rects.addWithoutMerging (r.removeFromTop (lineThickness)); | rects.addWithoutMerging (r.removeFromTop (lineThickness)); | ||||
| rects.addWithoutMerging (r.removeFromBottom (lineThickness)); | rects.addWithoutMerging (r.removeFromBottom (lineThickness)); | ||||
| @@ -52,21 +52,21 @@ public: | |||||
| } | } | ||||
| /** Creates a rectangle with a given position and size. */ | /** Creates a rectangle with a given position and size. */ | ||||
| Rectangle (const ValueType initialX, const ValueType initialY, | |||||
| const ValueType width, const ValueType height) noexcept | |||||
| Rectangle (ValueType initialX, ValueType initialY, | |||||
| ValueType width, ValueType height) noexcept | |||||
| : pos (initialX, initialY), | : pos (initialX, initialY), | ||||
| w (width), h (height) | w (width), h (height) | ||||
| { | { | ||||
| } | } | ||||
| /** Creates a rectangle with a given size, and a position of (0, 0). */ | /** Creates a rectangle with a given size, and a position of (0, 0). */ | ||||
| Rectangle (const ValueType width, const ValueType height) noexcept | |||||
| Rectangle (ValueType width, ValueType height) noexcept | |||||
| : w (width), h (height) | : w (width), h (height) | ||||
| { | { | ||||
| } | } | ||||
| /** Creates a Rectangle from the positions of two opposite corners. */ | /** Creates a Rectangle from the positions of two opposite corners. */ | ||||
| Rectangle (const Point<ValueType> corner1, const Point<ValueType> corner2) noexcept | |||||
| Rectangle (Point<ValueType> corner1, Point<ValueType> corner2) noexcept | |||||
| : pos (jmin (corner1.x, corner2.x), | : pos (jmin (corner1.x, corner2.x), | ||||
| jmin (corner1.y, corner2.y)), | jmin (corner1.y, corner2.y)), | ||||
| w (corner1.x - corner2.x), | w (corner1.x - corner2.x), | ||||
| @@ -80,8 +80,8 @@ public: | |||||
| The right and bottom values must be larger than the left and top ones, or the resulting | The right and bottom values must be larger than the left and top ones, or the resulting | ||||
| rectangle will have a negative size. | rectangle will have a negative size. | ||||
| */ | */ | ||||
| static Rectangle leftTopRightBottom (const ValueType left, const ValueType top, | |||||
| const ValueType right, const ValueType bottom) noexcept | |||||
| static Rectangle leftTopRightBottom (ValueType left, ValueType top, | |||||
| ValueType right, ValueType bottom) noexcept | |||||
| { | { | ||||
| return Rectangle (left, top, right - left, bottom - top); | return Rectangle (left, top, right - left, bottom - top); | ||||
| } | } | ||||
| @@ -134,17 +134,17 @@ public: | |||||
| /** Returns the aspect ratio of the rectangle's width / height. | /** Returns the aspect ratio of the rectangle's width / height. | ||||
| If widthOverHeight is true, it returns width / height; if widthOverHeight is false, | If widthOverHeight is true, it returns width / height; if widthOverHeight is false, | ||||
| it returns height / width. */ | it returns height / width. */ | ||||
| ValueType getAspectRatio (const bool widthOverHeight = true) const noexcept { return widthOverHeight ? w / h : h / w; } | |||||
| ValueType getAspectRatio (bool widthOverHeight = true) const noexcept { return widthOverHeight ? w / h : h / w; } | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the rectangle's top-left position as a Point. */ | /** Returns the rectangle's top-left position as a Point. */ | ||||
| inline Point<ValueType> getPosition() const noexcept { return pos; } | inline Point<ValueType> getPosition() const noexcept { return pos; } | ||||
| /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | ||||
| inline void setPosition (const Point<ValueType> newPos) noexcept { pos = newPos; } | |||||
| inline void setPosition (Point<ValueType> newPos) noexcept { pos = newPos; } | |||||
| /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ | ||||
| inline void setPosition (const ValueType newX, const ValueType newY) noexcept { pos.setXY (newX, newY); } | |||||
| inline void setPosition (ValueType newX, ValueType newY) noexcept { pos.setXY (newX, newY); } | |||||
| /** Returns the rectangle's top-left position as a Point. */ | /** Returns the rectangle's top-left position as a Point. */ | ||||
| Point<ValueType> getTopLeft() const noexcept { return pos; } | Point<ValueType> getTopLeft() const noexcept { return pos; } | ||||
| @@ -158,62 +158,75 @@ public: | |||||
| /** Returns the rectangle's bottom-right position as a Point. */ | /** Returns the rectangle's bottom-right position as a Point. */ | ||||
| Point<ValueType> getBottomRight() const noexcept { return Point<ValueType> (pos.x + w, pos.y + h); } | Point<ValueType> getBottomRight() const noexcept { return Point<ValueType> (pos.x + w, pos.y + h); } | ||||
| /** Returns the rectangle's left and right positions as a Range. */ | |||||
| Range<ValueType> getHorizontalRange() const noexcept { return Range<ValueType>::withStartAndLength (pos.x, w); } | |||||
| /** Returns the rectangle's top and bottom positions as a Range. */ | |||||
| Range<ValueType> getVerticalRange() const noexcept { return Range<ValueType>::withStartAndLength (pos.y, h); } | |||||
| /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ | /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ | ||||
| void setSize (const ValueType newWidth, const ValueType newHeight) noexcept { w = newWidth; h = newHeight; } | |||||
| void setSize (ValueType newWidth, ValueType newHeight) noexcept { w = newWidth; h = newHeight; } | |||||
| /** Changes all the rectangle's coordinates. */ | /** Changes all the rectangle's coordinates. */ | ||||
| void setBounds (const ValueType newX, const ValueType newY, | |||||
| const ValueType newWidth, const ValueType newHeight) noexcept { pos.x = newX; pos.y = newY; w = newWidth; h = newHeight; } | |||||
| void setBounds (ValueType newX, ValueType newY, | |||||
| ValueType newWidth, ValueType newHeight) noexcept { pos.x = newX; pos.y = newY; w = newWidth; h = newHeight; } | |||||
| /** Changes the rectangle's X coordinate */ | /** Changes the rectangle's X coordinate */ | ||||
| inline void setX (const ValueType newX) noexcept { pos.x = newX; } | |||||
| inline void setX (ValueType newX) noexcept { pos.x = newX; } | |||||
| /** Changes the rectangle's Y coordinate */ | /** Changes the rectangle's Y coordinate */ | ||||
| inline void setY (const ValueType newY) noexcept { pos.y = newY; } | |||||
| inline void setY (ValueType newY) noexcept { pos.y = newY; } | |||||
| /** Changes the rectangle's width */ | /** Changes the rectangle's width */ | ||||
| inline void setWidth (const ValueType newWidth) noexcept { w = newWidth; } | |||||
| inline void setWidth (ValueType newWidth) noexcept { w = newWidth; } | |||||
| /** Changes the rectangle's height */ | /** Changes the rectangle's height */ | ||||
| inline void setHeight (const ValueType newHeight) noexcept { h = newHeight; } | |||||
| inline void setHeight (ValueType newHeight) noexcept { h = newHeight; } | |||||
| /** Changes the position of the rectangle's centre (leaving its size unchanged). */ | /** Changes the position of the rectangle's centre (leaving its size unchanged). */ | ||||
| inline void setCentre (const ValueType newCentreX, const ValueType newCentreY) noexcept { pos.x = newCentreX - w / (ValueType) 2; pos.y = newCentreY - h / (ValueType) 2; } | |||||
| inline void setCentre (ValueType newCentreX, ValueType newCentreY) noexcept { pos.x = newCentreX - w / (ValueType) 2; | |||||
| pos.y = newCentreY - h / (ValueType) 2; } | |||||
| /** Changes the position of the rectangle's centre (leaving its size unchanged). */ | /** Changes the position of the rectangle's centre (leaving its size unchanged). */ | ||||
| inline void setCentre (const Point<ValueType> newCentre) noexcept { setCentre (newCentre.x, newCentre.y); } | |||||
| inline void setCentre (Point<ValueType> newCentre) noexcept { setCentre (newCentre.x, newCentre.y); } | |||||
| /** Changes the position of the rectangle's left and right edges. */ | |||||
| void setHorizontalRange (Range<ValueType> range) noexcept { pos.x = range.getStart(); w = range.getLength(); } | |||||
| /** Changes the position of the rectangle's top and bottom edges. */ | |||||
| void setVerticalRange (Range<ValueType> range) noexcept { pos.y = range.getStart(); h = range.getLength(); } | |||||
| /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */ | /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */ | ||||
| Rectangle withX (const ValueType newX) const noexcept { return Rectangle (newX, pos.y, w, h); } | |||||
| Rectangle withX (ValueType newX) const noexcept { return Rectangle (newX, pos.y, w, h); } | |||||
| /** Returns a rectangle which has the same size and x-position as this one, but with a different y-position. */ | /** Returns a rectangle which has the same size and x-position as this one, but with a different y-position. */ | ||||
| Rectangle withY (const ValueType newY) const noexcept { return Rectangle (pos.x, newY, w, h); } | |||||
| Rectangle withY (ValueType newY) const noexcept { return Rectangle (pos.x, newY, w, h); } | |||||
| /** Returns a rectangle with the same size as this one, but a new position. */ | /** Returns a rectangle with the same size as this one, but a new position. */ | ||||
| Rectangle withPosition (const ValueType newX, const ValueType newY) const noexcept { return Rectangle (newX, newY, w, h); } | |||||
| Rectangle withPosition (ValueType newX, ValueType newY) const noexcept { return Rectangle (newX, newY, w, h); } | |||||
| /** Returns a rectangle with the same size as this one, but a new position. */ | /** Returns a rectangle with the same size as this one, but a new position. */ | ||||
| Rectangle withPosition (const Point<ValueType> newPos) const noexcept { return Rectangle (newPos.x, newPos.y, w, h); } | |||||
| Rectangle withPosition (Point<ValueType> newPos) const noexcept { return Rectangle (newPos.x, newPos.y, w, h); } | |||||
| /** Returns a rectangle whose size is the same as this one, but whose top-left position is (0, 0). */ | /** Returns a rectangle whose size is the same as this one, but whose top-left position is (0, 0). */ | ||||
| Rectangle withZeroOrigin() const noexcept { return Rectangle (w, h); } | |||||
| Rectangle withZeroOrigin() const noexcept { return Rectangle (w, h); } | |||||
| /** Returns a rectangle with the same size as this one, but a new centre position. */ | /** Returns a rectangle with the same size as this one, but a new centre position. */ | ||||
| Rectangle withCentre (const Point<ValueType> newCentre) const noexcept { return Rectangle (newCentre.x - w / (ValueType) 2, | |||||
| newCentre.y - h / (ValueType) 2, w, h); } | |||||
| Rectangle withCentre (Point<ValueType> newCentre) const noexcept { return Rectangle (newCentre.x - w / (ValueType) 2, | |||||
| newCentre.y - h / (ValueType) 2, w, h); } | |||||
| /** Returns a rectangle which has the same position and height as this one, but with a different width. */ | /** Returns a rectangle which has the same position and height as this one, but with a different width. */ | ||||
| Rectangle withWidth (ValueType newWidth) const noexcept { return Rectangle (pos.x, pos.y, newWidth, h); } | |||||
| Rectangle withWidth (ValueType newWidth) const noexcept { return Rectangle (pos.x, pos.y, newWidth, h); } | |||||
| /** Returns a rectangle which has the same position and width as this one, but with a different height. */ | /** Returns a rectangle which has the same position and width as this one, but with a different height. */ | ||||
| Rectangle withHeight (ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, w, newHeight); } | |||||
| Rectangle withHeight (ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, w, newHeight); } | |||||
| /** Returns a rectangle with the same top-left position as this one, but a new size. */ | /** Returns a rectangle with the same top-left position as this one, but a new size. */ | ||||
| Rectangle withSize (ValueType newWidth, ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, newWidth, newHeight); } | |||||
| Rectangle withSize (ValueType newWidth, ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, newWidth, newHeight); } | |||||
| /** Returns a rectangle with the same centre position as this one, but a new size. */ | /** Returns a rectangle with the same centre position as this one, but a new size. */ | ||||
| Rectangle withSizeKeepingCentre (ValueType newWidth, ValueType newHeight) const noexcept { return Rectangle (pos.x + (w - newWidth) / (ValueType) 2, | |||||
| pos.y + (h - newHeight) / (ValueType) 2, newWidth, newHeight); } | |||||
| Rectangle withSizeKeepingCentre (ValueType newWidth, ValueType newHeight) const noexcept { return Rectangle (pos.x + (w - newWidth) / (ValueType) 2, | |||||
| pos.y + (h - newHeight) / (ValueType) 2, newWidth, newHeight); } | |||||
| /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. | /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. | ||||
| If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. | If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. | ||||
| @@ -277,41 +290,41 @@ public: | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Moves the rectangle's position by adding amount to its x and y coordinates. */ | /** Moves the rectangle's position by adding amount to its x and y coordinates. */ | ||||
| void translate (const ValueType deltaX, | |||||
| const ValueType deltaY) noexcept | |||||
| void translate (ValueType deltaX, | |||||
| ValueType deltaY) noexcept | |||||
| { | { | ||||
| pos.x += deltaX; | pos.x += deltaX; | ||||
| pos.y += deltaY; | pos.y += deltaY; | ||||
| } | } | ||||
| /** Returns a rectangle which is the same as this one moved by a given amount. */ | /** Returns a rectangle which is the same as this one moved by a given amount. */ | ||||
| Rectangle translated (const ValueType deltaX, | |||||
| const ValueType deltaY) const noexcept | |||||
| Rectangle translated (ValueType deltaX, | |||||
| ValueType deltaY) const noexcept | |||||
| { | { | ||||
| return Rectangle (pos.x + deltaX, pos.y + deltaY, w, h); | return Rectangle (pos.x + deltaX, pos.y + deltaY, w, h); | ||||
| } | } | ||||
| /** Returns a rectangle which is the same as this one moved by a given amount. */ | /** Returns a rectangle which is the same as this one moved by a given amount. */ | ||||
| Rectangle operator+ (const Point<ValueType> deltaPosition) const noexcept | |||||
| Rectangle operator+ (Point<ValueType> deltaPosition) const noexcept | |||||
| { | { | ||||
| return Rectangle (pos.x + deltaPosition.x, pos.y + deltaPosition.y, w, h); | return Rectangle (pos.x + deltaPosition.x, pos.y + deltaPosition.y, w, h); | ||||
| } | } | ||||
| /** Moves this rectangle by a given amount. */ | /** Moves this rectangle by a given amount. */ | ||||
| Rectangle& operator+= (const Point<ValueType> deltaPosition) noexcept | |||||
| Rectangle& operator+= (Point<ValueType> deltaPosition) noexcept | |||||
| { | { | ||||
| pos += deltaPosition; | pos += deltaPosition; | ||||
| return *this; | return *this; | ||||
| } | } | ||||
| /** Returns a rectangle which is the same as this one moved by a given amount. */ | /** Returns a rectangle which is the same as this one moved by a given amount. */ | ||||
| Rectangle operator- (const Point<ValueType> deltaPosition) const noexcept | |||||
| Rectangle operator- (Point<ValueType> deltaPosition) const noexcept | |||||
| { | { | ||||
| return Rectangle (pos.x - deltaPosition.x, pos.y - deltaPosition.y, w, h); | return Rectangle (pos.x - deltaPosition.x, pos.y - deltaPosition.y, w, h); | ||||
| } | } | ||||
| /** Moves this rectangle by a given amount. */ | /** Moves this rectangle by a given amount. */ | ||||
| Rectangle& operator-= (const Point<ValueType> deltaPosition) noexcept | |||||
| Rectangle& operator-= (Point<ValueType> deltaPosition) noexcept | |||||
| { | { | ||||
| pos -= deltaPosition; | pos -= deltaPosition; | ||||
| return *this; | return *this; | ||||
| @@ -396,8 +409,8 @@ public: | |||||
| Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). | Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). | ||||
| @see expanded, reduce, reduced | @see expanded, reduce, reduced | ||||
| */ | */ | ||||
| void expand (const ValueType deltaX, | |||||
| const ValueType deltaY) noexcept | |||||
| void expand (ValueType deltaX, | |||||
| ValueType deltaY) noexcept | |||||
| { | { | ||||
| const ValueType nw = jmax (ValueType(), w + deltaX * 2); | const ValueType nw = jmax (ValueType(), w + deltaX * 2); | ||||
| const ValueType nh = jmax (ValueType(), h + deltaY * 2); | const ValueType nh = jmax (ValueType(), h + deltaY * 2); | ||||
| @@ -409,8 +422,8 @@ public: | |||||
| Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). | Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). | ||||
| @see expand, reduce, reduced | @see expand, reduce, reduced | ||||
| */ | */ | ||||
| Rectangle expanded (const ValueType deltaX, | |||||
| const ValueType deltaY) const noexcept | |||||
| Rectangle expanded (ValueType deltaX, | |||||
| ValueType deltaY) const noexcept | |||||
| { | { | ||||
| const ValueType nw = jmax (ValueType(), w + deltaX * 2); | const ValueType nw = jmax (ValueType(), w + deltaX * 2); | ||||
| const ValueType nh = jmax (ValueType(), h + deltaY * 2); | const ValueType nh = jmax (ValueType(), h + deltaY * 2); | ||||
| @@ -422,7 +435,7 @@ public: | |||||
| Effectively, the rectangle returned is (x - delta, y - delta, w + delta * 2, h + delta * 2). | Effectively, the rectangle returned is (x - delta, y - delta, w + delta * 2, h + delta * 2). | ||||
| @see expand, reduce, reduced | @see expand, reduce, reduced | ||||
| */ | */ | ||||
| Rectangle expanded (const ValueType delta) const noexcept | |||||
| Rectangle expanded (ValueType delta) const noexcept | |||||
| { | { | ||||
| return expanded (delta, delta); | return expanded (delta, delta); | ||||
| } | } | ||||
| @@ -432,8 +445,8 @@ public: | |||||
| Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | ||||
| @see reduced, expand, expanded | @see reduced, expand, expanded | ||||
| */ | */ | ||||
| void reduce (const ValueType deltaX, | |||||
| const ValueType deltaY) noexcept | |||||
| void reduce (ValueType deltaX, | |||||
| ValueType deltaY) noexcept | |||||
| { | { | ||||
| expand (-deltaX, -deltaY); | expand (-deltaX, -deltaY); | ||||
| } | } | ||||
| @@ -443,8 +456,8 @@ public: | |||||
| Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | ||||
| @see reduce, expand, expanded | @see reduce, expand, expanded | ||||
| */ | */ | ||||
| Rectangle reduced (const ValueType deltaX, | |||||
| const ValueType deltaY) const noexcept | |||||
| Rectangle reduced (ValueType deltaX, | |||||
| ValueType deltaY) const noexcept | |||||
| { | { | ||||
| return expanded (-deltaX, -deltaY); | return expanded (-deltaX, -deltaY); | ||||
| } | } | ||||
| @@ -454,7 +467,7 @@ public: | |||||
| Effectively, the rectangle returned is (x + delta, y + delta, w - delta * 2, h - delta * 2). | Effectively, the rectangle returned is (x + delta, y + delta, w - delta * 2, h - delta * 2). | ||||
| @see reduce, expand, expanded | @see reduce, expand, expanded | ||||
| */ | */ | ||||
| Rectangle reduced (const ValueType delta) const noexcept | |||||
| Rectangle reduced (ValueType delta) const noexcept | |||||
| { | { | ||||
| return reduced (delta, delta); | return reduced (delta, delta); | ||||
| } | } | ||||
| @@ -468,7 +481,7 @@ public: | |||||
| If amountToRemove is greater than the height of this rectangle, it'll be clipped to | If amountToRemove is greater than the height of this rectangle, it'll be clipped to | ||||
| that value. | that value. | ||||
| */ | */ | ||||
| Rectangle removeFromTop (const ValueType amountToRemove) noexcept | |||||
| Rectangle removeFromTop (ValueType amountToRemove) noexcept | |||||
| { | { | ||||
| const Rectangle r (pos.x, pos.y, w, jmin (amountToRemove, h)); | const Rectangle r (pos.x, pos.y, w, jmin (amountToRemove, h)); | ||||
| pos.y += r.h; h -= r.h; | pos.y += r.h; h -= r.h; | ||||
| @@ -484,7 +497,7 @@ public: | |||||
| If amountToRemove is greater than the width of this rectangle, it'll be clipped to | If amountToRemove is greater than the width of this rectangle, it'll be clipped to | ||||
| that value. | that value. | ||||
| */ | */ | ||||
| Rectangle removeFromLeft (const ValueType amountToRemove) noexcept | |||||
| Rectangle removeFromLeft (ValueType amountToRemove) noexcept | |||||
| { | { | ||||
| const Rectangle r (pos.x, pos.y, jmin (amountToRemove, w), h); | const Rectangle r (pos.x, pos.y, jmin (amountToRemove, w), h); | ||||
| pos.x += r.w; w -= r.w; | pos.x += r.w; w -= r.w; | ||||
| @@ -533,13 +546,13 @@ public: | |||||
| bool operator!= (const Rectangle& other) const noexcept { return pos != other.pos || w != other.w || h != other.h; } | bool operator!= (const Rectangle& other) const noexcept { return pos != other.pos || w != other.w || h != other.h; } | ||||
| /** Returns true if this coordinate is inside the rectangle. */ | /** Returns true if this coordinate is inside the rectangle. */ | ||||
| bool contains (const ValueType xCoord, const ValueType yCoord) const noexcept | |||||
| bool contains (ValueType xCoord, ValueType yCoord) const noexcept | |||||
| { | { | ||||
| return xCoord >= pos.x && yCoord >= pos.y && xCoord < pos.x + w && yCoord < pos.y + h; | return xCoord >= pos.x && yCoord >= pos.y && xCoord < pos.x + w && yCoord < pos.y + h; | ||||
| } | } | ||||
| /** Returns true if this coordinate is inside the rectangle. */ | /** Returns true if this coordinate is inside the rectangle. */ | ||||
| bool contains (const Point<ValueType> point) const noexcept | |||||
| bool contains (Point<ValueType> point) const noexcept | |||||
| { | { | ||||
| return point.x >= pos.x && point.y >= pos.y && point.x < pos.x + w && point.y < pos.y + h; | return point.x >= pos.x && point.y >= pos.y && point.x < pos.x + w && point.y < pos.y + h; | ||||
| } | } | ||||
| @@ -552,7 +565,7 @@ public: | |||||
| } | } | ||||
| /** Returns the nearest point to the specified point that lies within this rectangle. */ | /** Returns the nearest point to the specified point that lies within this rectangle. */ | ||||
| Point<ValueType> getConstrainedPoint (const Point<ValueType> point) const noexcept | |||||
| Point<ValueType> getConstrainedPoint (Point<ValueType> point) const noexcept | |||||
| { | { | ||||
| return Point<ValueType> (jlimit (pos.x, pos.x + w, point.x), | return Point<ValueType> (jlimit (pos.x, pos.x + w, point.x), | ||||
| jlimit (pos.y, pos.y + h, point.y)); | jlimit (pos.y, pos.y + h, point.y)); | ||||
| @@ -59,6 +59,7 @@ void DrawableButton::setImages (const Drawable* normal, | |||||
| overImageOn = copyDrawableIfNotNull (overOn); | overImageOn = copyDrawableIfNotNull (overOn); | ||||
| downImageOn = copyDrawableIfNotNull (downOn); | downImageOn = copyDrawableIfNotNull (downOn); | ||||
| disabledImageOn = copyDrawableIfNotNull (disabledOn); | disabledImageOn = copyDrawableIfNotNull (disabledOn); | ||||
| currentImage = nullptr; | |||||
| buttonStateChanged(); | buttonStateChanged(); | ||||
| } | } | ||||
| @@ -1153,12 +1153,15 @@ void Component::setBounds (const int x, const int y, int w, int h) | |||||
| void Component::sendMovedResizedMessagesIfPending() | void Component::sendMovedResizedMessagesIfPending() | ||||
| { | { | ||||
| if (flags.isMoveCallbackPending || flags.isResizeCallbackPending) | |||||
| { | |||||
| sendMovedResizedMessages (flags.isMoveCallbackPending, flags.isResizeCallbackPending); | |||||
| const bool wasMoved = flags.isMoveCallbackPending; | |||||
| const bool wasResized = flags.isResizeCallbackPending; | |||||
| if (wasMoved || wasResized) | |||||
| { | |||||
| flags.isMoveCallbackPending = false; | flags.isMoveCallbackPending = false; | ||||
| flags.isResizeCallbackPending = false; | flags.isResizeCallbackPending = false; | ||||
| sendMovedResizedMessages (wasMoved, wasResized); | |||||
| } | } | ||||
| } | } | ||||
| @@ -812,7 +812,7 @@ public: | |||||
| virtual void childrenChanged(); | virtual void childrenChanged(); | ||||
| //============================================================================== | //============================================================================== | ||||
| /** Tests whether a given point inside the component. | |||||
| /** Tests whether a given point is inside the component. | |||||
| Overriding this method allows you to create components which only intercept | Overriding this method allows you to create components which only intercept | ||||
| mouse-clicks within a user-defined area. | mouse-clicks within a user-defined area. | ||||
| @@ -387,7 +387,7 @@ void FileBrowserComponent::fileDoubleClicked (const File& f) | |||||
| { | { | ||||
| setRoot (f); | setRoot (f); | ||||
| if ((flags & canSelectDirectories) != 0) | |||||
| if ((flags & canSelectDirectories) != 0 && (flags & doNotClearFileNameOnRootChange) == 0) | |||||
| filenameBox.setText (String::empty); | filenameBox.setText (String::empty); | ||||
| } | } | ||||
| else | else | ||||
| @@ -432,7 +432,9 @@ void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&) | |||||
| { | { | ||||
| setRoot (f); | setRoot (f); | ||||
| chosenFiles.clear(); | chosenFiles.clear(); | ||||
| filenameBox.setText (String::empty); | |||||
| if ((flags & doNotClearFileNameOnRootChange) == 0) | |||||
| filenameBox.setText (String()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -51,18 +51,19 @@ public: | |||||
| */ | */ | ||||
| enum FileChooserFlags | enum FileChooserFlags | ||||
| { | { | ||||
| openMode = 1, /**< specifies that the component should allow the user to | |||||
| choose an existing file with the intention of opening it. */ | |||||
| saveMode = 2, /**< specifies that the component should allow the user to specify | |||||
| the name of a file that will be used to save something. */ | |||||
| canSelectFiles = 4, /**< specifies that the user can select files (can be used in | |||||
| conjunction with canSelectDirectories). */ | |||||
| canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in | |||||
| conjuction with canSelectFiles). */ | |||||
| canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ | |||||
| useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ | |||||
| filenameBoxIsReadOnly = 64, /**< specifies that the user can't type directly into the filename box. */ | |||||
| warnAboutOverwriting = 128 /**< specifies that the dialog should warn about overwriting existing files (if possible). */ | |||||
| openMode = 1, /**< specifies that the component should allow the user to | |||||
| choose an existing file with the intention of opening it. */ | |||||
| saveMode = 2, /**< specifies that the component should allow the user to specify | |||||
| the name of a file that will be used to save something. */ | |||||
| canSelectFiles = 4, /**< specifies that the user can select files (can be used in | |||||
| conjunction with canSelectDirectories). */ | |||||
| canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in | |||||
| conjuction with canSelectFiles). */ | |||||
| canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */ | |||||
| useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */ | |||||
| filenameBoxIsReadOnly = 64, /**< specifies that the user can't type directly into the filename box. */ | |||||
| warnAboutOverwriting = 128, /**< specifies that the dialog should warn about overwriting existing files (if possible). */ | |||||
| doNotClearFileNameOnRootChange = 256 /**< specifies that the file name should not be cleared upon root change. */ | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -24,13 +24,13 @@ | |||||
| Viewport::Viewport (const String& name) | Viewport::Viewport (const String& name) | ||||
| : Component (name), | : Component (name), | ||||
| customScrollBarThickness(false), | |||||
| scrollBarThickness (0), | scrollBarThickness (0), | ||||
| singleStepX (16), | singleStepX (16), | ||||
| singleStepY (16), | singleStepY (16), | ||||
| showHScrollbar (true), | showHScrollbar (true), | ||||
| showVScrollbar (true), | showVScrollbar (true), | ||||
| deleteContent (true), | deleteContent (true), | ||||
| customScrollBarThickness (false), | |||||
| allowScrollingWithoutScrollbarV (false), | allowScrollingWithoutScrollbarV (false), | ||||
| allowScrollingWithoutScrollbarH (false), | allowScrollingWithoutScrollbarH (false), | ||||
| verticalScrollBar (true), | verticalScrollBar (true), | ||||
| @@ -55,7 +55,6 @@ Viewport::Viewport (const String& name) | |||||
| Viewport::~Viewport() | Viewport::~Viewport() | ||||
| { | { | ||||
| deleteContentComp(); | deleteContentComp(); | ||||
| mouseWheelTimer = nullptr; | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -382,30 +381,6 @@ static int rescaleMouseWheelDistance (float distance, int singleStepSize) noexce | |||||
| : jmax (distance, 1.0f)); | : jmax (distance, 1.0f)); | ||||
| } | } | ||||
| // This puts a temporary component overlay over the content component, to prevent | |||||
| // wheel events from reaching components inside it, so that while spinning a wheel | |||||
| // with momentum, it won't accidentally scroll any subcomponents of the viewport. | |||||
| struct Viewport::MouseWheelTimer : public Timer | |||||
| { | |||||
| MouseWheelTimer (Viewport& v) : viewport (v) | |||||
| { | |||||
| viewport.contentHolder.addAndMakeVisible (dummyOverlay); | |||||
| dummyOverlay.setAlwaysOnTop (true); | |||||
| dummyOverlay.setPaintingIsUnclipped (true); | |||||
| dummyOverlay.setBounds (viewport.contentHolder.getLocalBounds()); | |||||
| } | |||||
| void timerCallback() override | |||||
| { | |||||
| viewport.mouseWheelTimer = nullptr; | |||||
| } | |||||
| Component dummyOverlay; | |||||
| Viewport& viewport; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseWheelTimer) | |||||
| }; | |||||
| bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelDetails& wheel) | bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelDetails& wheel) | ||||
| { | { | ||||
| if (! (e.mods.isAltDown() || e.mods.isCtrlDown() || e.mods.isCommandDown())) | if (! (e.mods.isAltDown() || e.mods.isCtrlDown() || e.mods.isCommandDown())) | ||||
| @@ -436,11 +411,6 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelD | |||||
| if (pos != getViewPosition()) | if (pos != getViewPosition()) | ||||
| { | { | ||||
| if (mouseWheelTimer == nullptr) | |||||
| mouseWheelTimer = new MouseWheelTimer (*this); | |||||
| mouseWheelTimer->startTimer (300); | |||||
| setViewPosition (pos); | setViewPosition (pos); | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -263,15 +263,13 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| WeakReference<Component> contentComp; | WeakReference<Component> contentComp; | ||||
| Rectangle<int> lastVisibleArea; | Rectangle<int> lastVisibleArea; | ||||
| bool customScrollBarThickness; | |||||
| int scrollBarThickness; | int scrollBarThickness; | ||||
| int singleStepX, singleStepY; | int singleStepX, singleStepY; | ||||
| bool showHScrollbar, showVScrollbar, deleteContent; | bool showHScrollbar, showVScrollbar, deleteContent; | ||||
| bool customScrollBarThickness; | |||||
| bool allowScrollingWithoutScrollbarV, allowScrollingWithoutScrollbarH; | bool allowScrollingWithoutScrollbarV, allowScrollingWithoutScrollbarH; | ||||
| Component contentHolder; | Component contentHolder; | ||||
| ScrollBar verticalScrollBar, horizontalScrollBar; | ScrollBar verticalScrollBar, horizontalScrollBar; | ||||
| struct MouseWheelTimer; | |||||
| ScopedPointer<Timer> mouseWheelTimer; | |||||
| Point<int> viewportPosToCompPos (Point<int>) const; | Point<int> viewportPosToCompPos (Point<int>) const; | ||||
| @@ -43,7 +43,7 @@ public: | |||||
| imageOffset (offset), | imageOffset (offset), | ||||
| hasCheckedForExternalDrag (false) | hasCheckedForExternalDrag (false) | ||||
| { | { | ||||
| setSize (im.getWidth(), im.getHeight()); | |||||
| updateSize(); | |||||
| if (mouseDragSource == nullptr) | if (mouseDragSource == nullptr) | ||||
| mouseDragSource = sourceComponent; | mouseDragSource = sourceComponent; | ||||
| @@ -160,6 +160,13 @@ public: | |||||
| forceMouseCursorUpdate(); | forceMouseCursorUpdate(); | ||||
| } | } | ||||
| void updateImage (const Image& newImage) | |||||
| { | |||||
| image = newImage; | |||||
| updateSize(); | |||||
| repaint(); | |||||
| } | |||||
| void timerCallback() override | void timerCallback() override | ||||
| { | { | ||||
| forceMouseCursorUpdate(); | forceMouseCursorUpdate(); | ||||
| @@ -207,6 +214,11 @@ private: | |||||
| bool hasCheckedForExternalDrag; | bool hasCheckedForExternalDrag; | ||||
| Time lastTimeOverTarget; | Time lastTimeOverTarget; | ||||
| void updateSize() | |||||
| { | |||||
| setSize (image.getWidth(), image.getHeight()); | |||||
| } | |||||
| void forceMouseCursorUpdate() | void forceMouseCursorUpdate() | ||||
| { | { | ||||
| Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); | Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); | ||||
| @@ -472,6 +484,12 @@ var DragAndDropContainer::getCurrentDragDescription() const | |||||
| : var(); | : var(); | ||||
| } | } | ||||
| void DragAndDropContainer::setCurrentDragImage (const Image& newImage) | |||||
| { | |||||
| if (dragImageComponent != nullptr) | |||||
| dragImageComponent->updateImage (newImage); | |||||
| } | |||||
| DragAndDropContainer* DragAndDropContainer::findParentDragContainerFor (Component* c) | DragAndDropContainer* DragAndDropContainer::findParentDragContainerFor (Component* c) | ||||
| { | { | ||||
| return c != nullptr ? c->findParentComponentOfClass<DragAndDropContainer>() : nullptr; | return c != nullptr ? c->findParentComponentOfClass<DragAndDropContainer>() : nullptr; | ||||
| @@ -102,6 +102,9 @@ public: | |||||
| */ | */ | ||||
| var getCurrentDragDescription() const; | var getCurrentDragDescription() const; | ||||
| /** If a drag is in progress, this allows the image being shown to be dynamically updated. */ | |||||
| void setCurrentDragImage (const Image& newImage); | |||||
| /** Utility to find the DragAndDropContainer for a given Component. | /** Utility to find the DragAndDropContainer for a given Component. | ||||
| This will search up this component's parent hierarchy looking for the first | This will search up this component's parent hierarchy looking for the first | ||||
| @@ -354,6 +354,10 @@ struct MouseWheelDetails | |||||
| /** If true, then the wheel has continuous, un-stepped motion. */ | /** If true, then the wheel has continuous, un-stepped motion. */ | ||||
| bool isSmooth; | bool isSmooth; | ||||
| /** If true, then this event is part of the intertial momentum phase that follows | |||||
| the wheel being released. */ | |||||
| bool isInertial; | |||||
| }; | }; | ||||
| @@ -331,10 +331,17 @@ public: | |||||
| Time time, const MouseWheelDetails& wheel) | Time time, const MouseWheelDetails& wheel) | ||||
| { | { | ||||
| Desktop::getInstance().incrementMouseWheelCounter(); | Desktop::getInstance().incrementMouseWheelCounter(); | ||||
| Point<float> screenPos; | Point<float> screenPos; | ||||
| if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos)) | |||||
| sendMouseWheel (*current, screenPos, time, wheel); | |||||
| // This will make sure that when the wheel spins in its inertial phase, any events | |||||
| // continue to be sent to the last component that the mouse was over when it was being | |||||
| // actively controlled by the user. This avoids confusion when scrolling through nested | |||||
| // scrollable components. | |||||
| if (lastNonInertialWheelTarget == nullptr || ! wheel.isInertial) | |||||
| lastNonInertialWheelTarget = getTargetForGesture (peer, positionWithinPeer, time, screenPos); | |||||
| if (Component* target = lastNonInertialWheelTarget) | |||||
| sendMouseWheel (*target, screenPos, time, wheel); | |||||
| } | } | ||||
| void handleMagnifyGesture (ComponentPeer& peer, Point<float> positionWithinPeer, | void handleMagnifyGesture (ComponentPeer& peer, Point<float> positionWithinPeer, | ||||
| @@ -467,7 +474,7 @@ public: | |||||
| bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | ||||
| private: | private: | ||||
| WeakReference<Component> componentUnderMouse; | |||||
| WeakReference<Component> componentUnderMouse, lastNonInertialWheelTarget; | |||||
| ComponentPeer* lastPeer; | ComponentPeer* lastPeer; | ||||
| void* currentCursorHandle; | void* currentCursorHandle; | ||||
| @@ -512,6 +519,7 @@ private: | |||||
| mouseDowns[0].peerID = 0; | mouseDowns[0].peerID = 0; | ||||
| mouseMovedSignificantlySincePressed = false; | mouseMovedSignificantlySincePressed = false; | ||||
| lastNonInertialWheelTarget = nullptr; | |||||
| } | } | ||||
| void registerMouseDrag (Point<float> screenPos) noexcept | void registerMouseDrag (Point<float> screenPos) noexcept | ||||
| @@ -112,7 +112,8 @@ public: | |||||
| : ComponentPeer (comp, windowStyleFlags), | : ComponentPeer (comp, windowStyleFlags), | ||||
| usingAndroidGraphics (false), | usingAndroidGraphics (false), | ||||
| fullScreen (false), | fullScreen (false), | ||||
| sizeAllocated (0) | |||||
| sizeAllocated (0), | |||||
| scale ((float) Desktop::getInstance().getDisplays().getMainDisplay().scale) | |||||
| { | { | ||||
| // NB: must not put this in the initialiser list, as it invokes a callback, | // NB: must not put this in the initialiser list, as it invokes a callback, | ||||
| // which will fail if the peer is only half-constructed. | // which will fail if the peer is only half-constructed. | ||||
| @@ -189,8 +190,10 @@ public: | |||||
| view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get()); | view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get()); | ||||
| } | } | ||||
| void setBounds (const Rectangle<int>& r, bool isNowFullScreen) override | |||||
| void setBounds (const Rectangle<int>& userRect, bool isNowFullScreen) override | |||||
| { | { | ||||
| Rectangle<int> r = userRect * scale; | |||||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | if (MessageManager::getInstance()->isThisTheMessageThread()) | ||||
| { | { | ||||
| fullScreen = isNowFullScreen; | fullScreen = isNowFullScreen; | ||||
| @@ -224,7 +227,7 @@ public: | |||||
| return Rectangle<int> (view.callIntMethod (ComponentPeerView.getLeft), | return Rectangle<int> (view.callIntMethod (ComponentPeerView.getLeft), | ||||
| view.callIntMethod (ComponentPeerView.getTop), | view.callIntMethod (ComponentPeerView.getTop), | ||||
| view.callIntMethod (ComponentPeerView.getWidth), | view.callIntMethod (ComponentPeerView.getWidth), | ||||
| view.callIntMethod (ComponentPeerView.getHeight)); | |||||
| view.callIntMethod (ComponentPeerView.getHeight)) / scale; | |||||
| } | } | ||||
| void handleScreenSizeChange() | void handleScreenSizeChange() | ||||
| @@ -238,7 +241,7 @@ public: | |||||
| Point<int> getScreenPosition() const | Point<int> getScreenPosition() const | ||||
| { | { | ||||
| return Point<int> (view.callIntMethod (ComponentPeerView.getLeft), | return Point<int> (view.callIntMethod (ComponentPeerView.getLeft), | ||||
| view.callIntMethod (ComponentPeerView.getTop)); | |||||
| view.callIntMethod (ComponentPeerView.getTop)) / scale; | |||||
| } | } | ||||
| Point<float> localToGlobal (Point<float> relativePosition) override | Point<float> localToGlobal (Point<float> relativePosition) override | ||||
| @@ -291,7 +294,8 @@ public: | |||||
| return isPositiveAndBelow (localPos.x, component.getWidth()) | return isPositiveAndBelow (localPos.x, component.getWidth()) | ||||
| && isPositiveAndBelow (localPos.y, component.getHeight()) | && isPositiveAndBelow (localPos.y, component.getHeight()) | ||||
| && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, | && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, | ||||
| localPos.x, localPos.y)); | |||||
| localPos.x * scale, | |||||
| localPos.y * scale)); | |||||
| } | } | ||||
| BorderSize<int> getFrameSize() const override | BorderSize<int> getFrameSize() const override | ||||
| @@ -322,19 +326,21 @@ public: | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void handleMouseDownCallback (int index, Point<float> pos, int64 time) | |||||
| void handleMouseDownCallback (int index, Point<float> sysPos, int64 time) | |||||
| { | { | ||||
| Point<float> pos = sysPos / scale; | |||||
| lastMousePos = pos; | lastMousePos = pos; | ||||
| // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | ||||
| handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time); | handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time); | ||||
| if (isValidPeer (this)) | if (isValidPeer (this)) | ||||
| handleMouseDragCallback (index, pos, time); | |||||
| handleMouseDragCallback (index, sysPos, time); | |||||
| } | } | ||||
| void handleMouseDragCallback (int index, Point<float> pos, int64 time) | void handleMouseDragCallback (int index, Point<float> pos, int64 time) | ||||
| { | { | ||||
| pos /= scale; | |||||
| lastMousePos = pos; | lastMousePos = pos; | ||||
| jassert (index < 64); | jassert (index < 64); | ||||
| @@ -346,6 +352,7 @@ public: | |||||
| void handleMouseUpCallback (int index, Point<float> pos, int64 time) | void handleMouseUpCallback (int index, Point<float> pos, int64 time) | ||||
| { | { | ||||
| pos /= scale; | |||||
| lastMousePos = pos; | lastMousePos = pos; | ||||
| jassert (index < 64); | jassert (index < 64); | ||||
| @@ -441,6 +448,7 @@ public: | |||||
| { | { | ||||
| LowLevelGraphicsSoftwareRenderer g (temp); | LowLevelGraphicsSoftwareRenderer g (temp); | ||||
| g.setOrigin (-clip.getPosition()); | g.setOrigin (-clip.getPosition()); | ||||
| g.addTransform (AffineTransform::scale (scale)); | |||||
| handlePaint (g); | handlePaint (g); | ||||
| } | } | ||||
| } | } | ||||
| @@ -453,8 +461,10 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| void repaint (const Rectangle<int>& area) override | |||||
| void repaint (const Rectangle<int>& userArea) override | |||||
| { | { | ||||
| Rectangle<int> area = userArea * scale; | |||||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | if (MessageManager::getInstance()->isThisTheMessageThread()) | ||||
| { | { | ||||
| view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); | view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); | ||||
| @@ -507,6 +517,7 @@ private: | |||||
| GlobalRef buffer; | GlobalRef buffer; | ||||
| bool usingAndroidGraphics, fullScreen; | bool usingAndroidGraphics, fullScreen; | ||||
| int sizeAllocated; | int sizeAllocated; | ||||
| float scale; | |||||
| class PreallocatedImage : public ImagePixelData | class PreallocatedImage : public ImagePixelData | ||||
| { | { | ||||
| @@ -723,11 +734,12 @@ bool juce_areThereAnyAlwaysOnTopWindows() | |||||
| void Desktop::Displays::findDisplays (float masterScale) | void Desktop::Displays::findDisplays (float masterScale) | ||||
| { | { | ||||
| Display d; | Display d; | ||||
| d.userArea = d.totalArea = Rectangle<int> (android.screenWidth, | |||||
| android.screenHeight) / masterScale; | |||||
| d.isMain = true; | d.isMain = true; | ||||
| d.scale = masterScale; | |||||
| d.dpi = android.dpi; | d.dpi = android.dpi; | ||||
| d.scale = masterScale * (d.dpi / 150.); | |||||
| d.userArea = d.totalArea = Rectangle<int> (android.screenWidth, | |||||
| android.screenHeight) / d.scale; | |||||
| displays.add (d); | displays.add (d); | ||||
| } | } | ||||
| @@ -131,11 +131,11 @@ static void addZenityArgs (StringArray& args, String& separator, | |||||
| if (filters.isNotEmpty() && filters != "*" && filters != "*.*") | if (filters.isNotEmpty() && filters != "*" && filters != "*.*") | ||||
| { | { | ||||
| args.add ("--file-filter"); | |||||
| args.add (filters.replaceCharacter (';', ' ')); | |||||
| StringArray tokens; | |||||
| tokens.addTokens (filters, ";,|", "\""); | |||||
| args.add ("--file-filter"); | |||||
| args.add ("All files | *"); | |||||
| for (int i = 0; i < tokens.size(); ++i) | |||||
| args.add ("--file-filter='" + tokens[i] + "'"); | |||||
| } | } | ||||
| if (file.isDirectory()) | if (file.isDirectory()) | ||||
| @@ -978,9 +978,9 @@ private: | |||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_USE_XRANDR | #if JUCE_USE_XRANDR | ||||
| friend class ContainerDeletePolicy<XRRScreenResources>; | |||||
| friend class ContainerDeletePolicy<XRROutputInfo>; | |||||
| friend class ContainerDeletePolicy<XRRCrtcInfo>; | |||||
| friend struct ContainerDeletePolicy<XRRScreenResources>; | |||||
| friend struct ContainerDeletePolicy<XRROutputInfo>; | |||||
| friend struct ContainerDeletePolicy<XRRCrtcInfo>; | |||||
| class XRandrWrapper | class XRandrWrapper | ||||
| { | { | ||||
| @@ -1062,9 +1062,9 @@ private: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| friend class ContainerDeletePolicy<XRRScreenResources>; | |||||
| friend class ContainerDeletePolicy<XRROutputInfo>; | |||||
| friend class ContainerDeletePolicy<XRRCrtcInfo>; | |||||
| friend struct ContainerDeletePolicy<XRRScreenResources>; | |||||
| friend struct ContainerDeletePolicy<XRROutputInfo>; | |||||
| friend struct ContainerDeletePolicy<XRRCrtcInfo>; | |||||
| void freeScreenResources (XRRScreenResources* ptr) | void freeScreenResources (XRRScreenResources* ptr) | ||||
| { | { | ||||
| @@ -2209,6 +2209,7 @@ public: | |||||
| wheel.deltaY = amount; | wheel.deltaY = amount; | ||||
| wheel.isReversed = false; | wheel.isReversed = false; | ||||
| wheel.isSmooth = false; | wheel.isSmooth = false; | ||||
| wheel.isInertial = false; | |||||
| handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel); | handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel); | ||||
| } | } | ||||
| @@ -3723,12 +3724,45 @@ void Desktop::Displays::findDisplays (float masterScale) | |||||
| { | { | ||||
| DisplayGeometry& geometry = DisplayGeometry::getOrCreateInstance (display, masterScale); | DisplayGeometry& geometry = DisplayGeometry::getOrCreateInstance (display, masterScale); | ||||
| // add the main display first | |||||
| int mainDisplayIdx; | |||||
| for (mainDisplayIdx = 0; mainDisplayIdx < geometry.infos.size(); ++mainDisplayIdx) | |||||
| { | |||||
| const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (mainDisplayIdx); | |||||
| if (info.isMain) | |||||
| break; | |||||
| } | |||||
| // no main display found then use the first | |||||
| if (mainDisplayIdx >= geometry.infos.size()) | |||||
| mainDisplayIdx = 0; | |||||
| // add the main display | |||||
| { | |||||
| const DisplayGeometry::ExtendedInfo& info = | |||||
| geometry.infos.getReference (mainDisplayIdx); | |||||
| Desktop::Displays::Display d; | |||||
| d.isMain = true; | |||||
| d.scale = masterScale * info.scale; | |||||
| d.dpi = info.dpi; | |||||
| d.totalArea = DisplayGeometry::physicalToScaled (info.totalBounds); | |||||
| d.userArea = (info.usableBounds / d.scale) + info.topLeftScaled; | |||||
| displays.add (d); | |||||
| } | |||||
| for (int i = 0; i < geometry.infos.size(); ++i) | for (int i = 0; i < geometry.infos.size(); ++i) | ||||
| { | { | ||||
| // don't add the main display a second time | |||||
| if (i == mainDisplayIdx) | |||||
| continue; | |||||
| const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (i); | const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (i); | ||||
| Desktop::Displays::Display d; | Desktop::Displays::Display d; | ||||
| d.isMain = info.isMain; | |||||
| d.isMain = false; | |||||
| d.scale = masterScale * info.scale; | d.scale = masterScale * info.scale; | ||||
| d.dpi = info.dpi; | d.dpi = info.dpi; | ||||
| @@ -50,34 +50,62 @@ namespace MouseCursorHelpers | |||||
| } | } | ||||
| } | } | ||||
| static void* fromWebKitFile (const char* filename, float hx, float hy) | |||||
| static NSCursor* fromNSImage (NSImage* im, NSPoint hotspot) | |||||
| { | { | ||||
| FileInputStream fileStream (File ("/System/Library/Frameworks/WebKit.framework/Frameworks/WebCore.framework/Resources") | |||||
| .getChildFile (filename)); | |||||
| NSCursor* c = [[NSCursor alloc] initWithImage: im | |||||
| hotSpot: hotspot]; | |||||
| [im release]; | |||||
| return c; | |||||
| } | |||||
| if (fileStream.openedOk()) | |||||
| static void* fromHIServices (const char* filename) | |||||
| { | |||||
| JUCE_AUTORELEASEPOOL | |||||
| { | { | ||||
| BufferedInputStream buf (fileStream, 4096); | |||||
| const String cursorPath (String ("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/" | |||||
| "HIServices.framework/Versions/A/Resources/cursors/") | |||||
| + filename); | |||||
| PNGImageFormat pngFormat; | |||||
| Image im (pngFormat.decodeImage (buf)); | |||||
| NSImage* originalImage = [[NSImage alloc] initByReferencingFile: juceStringToNS (cursorPath + "/cursor.pdf")]; | |||||
| NSSize originalSize = [originalImage size]; | |||||
| NSImage* resultImage = [[NSImage alloc] initWithSize: originalSize]; | |||||
| if (im.isValid()) | |||||
| return CustomMouseCursorInfo (im, (int) (hx * im.getWidth()), | |||||
| (int) (hy * im.getHeight())).create(); | |||||
| } | |||||
| for (int scale = 1; scale <= 4; ++scale) | |||||
| { | |||||
| NSAffineTransform* scaleTransform = [NSAffineTransform transform]; | |||||
| [scaleTransform scaleBy: (float) scale]; | |||||
| if (CGImageRef rasterCGImage = [originalImage CGImageForProposedRect: nil | |||||
| context: nil | |||||
| hints: [NSDictionary dictionaryWithObjectsAndKeys: | |||||
| NSImageHintCTM, scaleTransform, nil]]) | |||||
| { | |||||
| NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: rasterCGImage]; | |||||
| [imageRep setSize: originalSize]; | |||||
| [resultImage addRepresentation: imageRep]; | |||||
| [imageRep release]; | |||||
| } | |||||
| else | |||||
| { | |||||
| return nil; | |||||
| } | |||||
| } | |||||
| return nullptr; | |||||
| NSDictionary* info = [NSDictionary dictionaryWithContentsOfFile: juceStringToNS (cursorPath + "/info.plist")]; | |||||
| const float hotspotX = (float) [[info valueForKey: nsStringLiteral ("hotx")] doubleValue]; | |||||
| const float hotspotY = (float) [[info valueForKey: nsStringLiteral ("hoty")] doubleValue]; | |||||
| return fromNSImage (resultImage, NSMakePoint (hotspotX, hotspotY)); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| void* CustomMouseCursorInfo::create() const | void* CustomMouseCursorInfo::create() const | ||||
| { | { | ||||
| NSImage* im = MouseCursorHelpers::createNSImage (image); | |||||
| NSCursor* c = [[NSCursor alloc] initWithImage: im | |||||
| hotSpot: NSMakePoint (hotspot.x, hotspot.y)]; | |||||
| [im release]; | |||||
| return c; | |||||
| return MouseCursorHelpers::fromNSImage (MouseCursorHelpers::createNSImage (image), | |||||
| NSMakePoint (hotspot.x, hotspot.y)); | |||||
| } | } | ||||
| void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type) | void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type) | ||||
| @@ -102,9 +130,10 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||||
| case CopyingCursor: | case CopyingCursor: | ||||
| { | { | ||||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 | #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 | ||||
| if (void* m = MouseCursorHelpers::fromWebKitFile ("copyCursor.png", 0, 0)) | |||||
| if (void* m = MouseCursorHelpers::fromHIServices ("copy")) | |||||
| return m; | return m; | ||||
| #endif | #endif | ||||
| c = [NSCursor dragCopyCursor]; // added in 10.6 | c = [NSCursor dragCopyCursor]; // added in 10.6 | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -112,10 +141,14 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||||
| case UpDownResizeCursor: | case UpDownResizeCursor: | ||||
| case TopEdgeResizeCursor: | case TopEdgeResizeCursor: | ||||
| case BottomEdgeResizeCursor: | case BottomEdgeResizeCursor: | ||||
| return MouseCursorHelpers::fromWebKitFile ("northSouthResizeCursor.png", 0.5f, 0.5f); | |||||
| if (void* m = MouseCursorHelpers::fromHIServices ("resizenorthsouth")) | |||||
| return m; | |||||
| c = [NSCursor resizeUpDownCursor]; | |||||
| break; | |||||
| case LeftRightResizeCursor: | case LeftRightResizeCursor: | ||||
| if (void* m = MouseCursorHelpers::fromWebKitFile ("eastWestResizeCursor.png", 0.5f, 0.5f)) | |||||
| if (void* m = MouseCursorHelpers::fromHIServices ("resizeeastwest")) | |||||
| return m; | return m; | ||||
| c = [NSCursor resizeLeftRightCursor]; | c = [NSCursor resizeLeftRightCursor]; | ||||
| @@ -123,14 +156,14 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||||
| case TopLeftCornerResizeCursor: | case TopLeftCornerResizeCursor: | ||||
| case BottomRightCornerResizeCursor: | case BottomRightCornerResizeCursor: | ||||
| return MouseCursorHelpers::fromWebKitFile ("northWestSouthEastResizeCursor.png", 0.5f, 0.5f); | |||||
| return MouseCursorHelpers::fromHIServices ("resizenorthwestsoutheast"); | |||||
| case TopRightCornerResizeCursor: | case TopRightCornerResizeCursor: | ||||
| case BottomLeftCornerResizeCursor: | case BottomLeftCornerResizeCursor: | ||||
| return MouseCursorHelpers::fromWebKitFile ("northEastSouthWestResizeCursor.png", 0.5f, 0.5f); | |||||
| return MouseCursorHelpers::fromHIServices ("resizenortheastsouthwest"); | |||||
| case UpDownLeftRightResizeCursor: | case UpDownLeftRightResizeCursor: | ||||
| return MouseCursorHelpers::fromWebKitFile ("moveCursor.png", 0.5f, 0.5f); | |||||
| return MouseCursorHelpers::fromHIServices ("move"); | |||||
| default: | default: | ||||
| jassertfalse; | jassertfalse; | ||||
| @@ -497,10 +497,7 @@ public: | |||||
| void toBehind (ComponentPeer* other) override | void toBehind (ComponentPeer* other) override | ||||
| { | { | ||||
| NSViewComponentPeer* const otherPeer = dynamic_cast<NSViewComponentPeer*> (other); | |||||
| jassert (otherPeer != nullptr); // wrong type of window? | |||||
| if (otherPeer != nullptr) | |||||
| if (NSViewComponentPeer* const otherPeer = dynamic_cast<NSViewComponentPeer*> (other)) | |||||
| { | { | ||||
| if (isSharedWindow) | if (isSharedWindow) | ||||
| { | { | ||||
| @@ -514,6 +511,10 @@ public: | |||||
| relativeTo: [otherPeer->window windowNumber]]; | relativeTo: [otherPeer->window windowNumber]]; | ||||
| } | } | ||||
| } | } | ||||
| else | |||||
| { | |||||
| jassertfalse; // wrong type of window? | |||||
| } | |||||
| } | } | ||||
| void setIcon (const Image&) override | void setIcon (const Image&) override | ||||
| @@ -620,6 +621,7 @@ public: | |||||
| wheel.deltaY = 0; | wheel.deltaY = 0; | ||||
| wheel.isReversed = false; | wheel.isReversed = false; | ||||
| wheel.isSmooth = false; | wheel.isSmooth = false; | ||||
| wheel.isInertial = false; | |||||
| #if ! JUCE_PPC | #if ! JUCE_PPC | ||||
| @try | @try | ||||
| @@ -628,6 +630,8 @@ public: | |||||
| if ([ev respondsToSelector: @selector (isDirectionInvertedFromDevice)]) | if ([ev respondsToSelector: @selector (isDirectionInvertedFromDevice)]) | ||||
| wheel.isReversed = [ev isDirectionInvertedFromDevice]; | wheel.isReversed = [ev isDirectionInvertedFromDevice]; | ||||
| wheel.isInertial = ([ev momentumPhase] != NSEventPhaseNone); | |||||
| if ([ev respondsToSelector: @selector (hasPreciseScrollingDeltas)]) | if ([ev respondsToSelector: @selector (hasPreciseScrollingDeltas)]) | ||||
| { | { | ||||
| if ([ev hasPreciseScrollingDeltas]) | if ([ev hasPreciseScrollingDeltas]) | ||||
| @@ -218,6 +218,8 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||||
| info.customComponent->enterModalState(); | info.customComponent->enterModalState(); | ||||
| } | } | ||||
| const StringRef separatorTokens (";,|"); | |||||
| const size_t filterSpaceNumChars = 2048; | const size_t filterSpaceNumChars = 2048; | ||||
| HeapBlock<WCHAR> filters; | HeapBlock<WCHAR> filters; | ||||
| filters.calloc (filterSpaceNumChars); | filters.calloc (filterSpaceNumChars); | ||||
| @@ -225,6 +227,10 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||||
| filter.copyToUTF16 (filters + (bytesWritten / sizeof (WCHAR)), | filter.copyToUTF16 (filters + (bytesWritten / sizeof (WCHAR)), | ||||
| ((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten)); | ((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten)); | ||||
| for (int i = 0; i < filterSpaceNumChars; ++i) | |||||
| if (separatorTokens.text.indexOf ((juce_wchar) filters[i]) >= 0) | |||||
| filters[i] = 0; | |||||
| OPENFILENAMEW of = { 0 }; | OPENFILENAMEW of = { 0 }; | ||||
| String localPath (info.initialPath); | String localPath (info.initialPath); | ||||
| @@ -249,7 +255,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||||
| if (isSaveDialogue) | if (isSaveDialogue) | ||||
| { | { | ||||
| StringArray tokens; | StringArray tokens; | ||||
| tokens.addTokens (filter, ";,", "\"'"); | |||||
| tokens.addTokens (filter, separatorTokens, "\"'"); | |||||
| tokens.trim(); | tokens.trim(); | ||||
| tokens.removeEmptyStrings(); | tokens.removeEmptyStrings(); | ||||
| @@ -1820,6 +1820,7 @@ private: | |||||
| wheel.deltaY = isVertical ? amount / 256.0f : 0.0f; | wheel.deltaY = isVertical ? amount / 256.0f : 0.0f; | ||||
| wheel.isReversed = false; | wheel.isReversed = false; | ||||
| wheel.isSmooth = false; | wheel.isSmooth = false; | ||||
| wheel.isInertial = false; | |||||
| Point<float> localPos; | Point<float> localPos; | ||||
| if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) | if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) | ||||
| @@ -2968,24 +2969,27 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) | |||||
| { | { | ||||
| SHORT k = (SHORT) keyCode; | SHORT k = (SHORT) keyCode; | ||||
| if ((keyCode & extendedKeyModifier) == 0 | |||||
| && (k >= (SHORT) 'a' && k <= (SHORT) 'z')) | |||||
| k += (SHORT) 'A' - (SHORT) 'a'; | |||||
| const SHORT translatedValues[] = { (SHORT) ',', VK_OEM_COMMA, | |||||
| (SHORT) '+', VK_OEM_PLUS, | |||||
| (SHORT) '-', VK_OEM_MINUS, | |||||
| (SHORT) '.', VK_OEM_PERIOD, | |||||
| (SHORT) ';', VK_OEM_1, | |||||
| (SHORT) ':', VK_OEM_1, | |||||
| (SHORT) '/', VK_OEM_2, | |||||
| (SHORT) '?', VK_OEM_2, | |||||
| (SHORT) '[', VK_OEM_4, | |||||
| (SHORT) ']', VK_OEM_6 }; | |||||
| for (int i = 0; i < numElementsInArray (translatedValues); i += 2) | |||||
| if (k == translatedValues [i]) | |||||
| k = translatedValues [i + 1]; | |||||
| if ((keyCode & extendedKeyModifier) == 0) | |||||
| { | |||||
| if (k >= (SHORT) 'a' && k <= (SHORT) 'z') | |||||
| k += (SHORT) 'A' - (SHORT) 'a'; | |||||
| // Only translate if extendedKeyModifier flag is not set | |||||
| const SHORT translatedValues[] = { (SHORT) ',', VK_OEM_COMMA, | |||||
| (SHORT) '+', VK_OEM_PLUS, | |||||
| (SHORT) '-', VK_OEM_MINUS, | |||||
| (SHORT) '.', VK_OEM_PERIOD, | |||||
| (SHORT) ';', VK_OEM_1, | |||||
| (SHORT) ':', VK_OEM_1, | |||||
| (SHORT) '/', VK_OEM_2, | |||||
| (SHORT) '?', VK_OEM_2, | |||||
| (SHORT) '[', VK_OEM_4, | |||||
| (SHORT) ']', VK_OEM_6 }; | |||||
| for (int i = 0; i < numElementsInArray (translatedValues); i += 2) | |||||
| if (k == translatedValues [i]) | |||||
| k = translatedValues [i + 1]; | |||||
| } | |||||
| return HWNDComponentPeer::isKeyDown (k); | return HWNDComponentPeer::isKeyDown (k); | ||||
| } | } | ||||
| @@ -32,13 +32,10 @@ class AllComponentRepainter : private Timer, | |||||
| private DeletedAtShutdown | private DeletedAtShutdown | ||||
| { | { | ||||
| public: | public: | ||||
| AllComponentRepainter() {} | |||||
| AllComponentRepainter() {} | |||||
| ~AllComponentRepainter() { clearSingletonInstance(); } | |||||
| static AllComponentRepainter& getInstance() | |||||
| { | |||||
| static AllComponentRepainter* instance = new AllComponentRepainter(); | |||||
| return *instance; | |||||
| } | |||||
| juce_DeclareSingleton (AllComponentRepainter, false) | |||||
| void trigger() | void trigger() | ||||
| { | { | ||||
| @@ -51,26 +48,45 @@ private: | |||||
| { | { | ||||
| stopTimer(); | stopTimer(); | ||||
| Array<Component*> alreadyDone; | |||||
| for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;) | for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;) | ||||
| if (Component* c = TopLevelWindow::getTopLevelWindow(i)) | if (Component* c = TopLevelWindow::getTopLevelWindow(i)) | ||||
| repaintAndResizeAllComps (c); | |||||
| repaintAndResizeAllComps (c, alreadyDone); | |||||
| Desktop& desktop = Desktop::getInstance(); | |||||
| for (int i = desktop.getNumComponents(); --i >= 0;) | |||||
| if (Component* c = desktop.getComponent(i)) | |||||
| repaintAndResizeAllComps (c, alreadyDone); | |||||
| } | } | ||||
| static void repaintAndResizeAllComps (Component::SafePointer<Component> c) | |||||
| static void repaintAndResizeAllComps (Component::SafePointer<Component> c, | |||||
| Array<Component*>& alreadyDone) | |||||
| { | { | ||||
| if (c->isVisible()) | |||||
| if (c->isVisible() && ! alreadyDone.contains (c)) | |||||
| { | { | ||||
| c->repaint(); | c->repaint(); | ||||
| c->resized(); | c->resized(); | ||||
| for (int i = c->getNumChildComponents(); --i >= 0;) | for (int i = c->getNumChildComponents(); --i >= 0;) | ||||
| if (c != nullptr) | |||||
| if (Component* child = c->getChildComponent(i)) | |||||
| repaintAndResizeAllComps (child); | |||||
| { | |||||
| if (Component* child = c->getChildComponent(i)) | |||||
| { | |||||
| repaintAndResizeAllComps (child, alreadyDone); | |||||
| alreadyDone.add (child); | |||||
| } | |||||
| if (c == nullptr) | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| juce_ImplementSingleton (AllComponentRepainter) | |||||
| juce_ImplementSingleton (ValueList) | |||||
| //============================================================================== | //============================================================================== | ||||
| int64 parseInt (String s) | int64 parseInt (String s) | ||||
| { | { | ||||
| @@ -175,7 +191,7 @@ void LivePropertyEditorBase::applyNewValue (const String& s) | |||||
| selectOriginalValue(); | selectOriginalValue(); | ||||
| valueEditor.setText (s, dontSendNotification); | valueEditor.setText (s, dontSendNotification); | ||||
| AllComponentRepainter::getInstance().trigger(); | |||||
| AllComponentRepainter::getInstance()->trigger(); | |||||
| } | } | ||||
| void LivePropertyEditorBase::selectOriginalValue() | void LivePropertyEditorBase::selectOriginalValue() | ||||
| @@ -333,14 +349,8 @@ public: | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| ValueList::ValueList() {} | |||||
| ValueList::~ValueList() {} | |||||
| ValueList& ValueList::getInstance() | |||||
| { | |||||
| static ValueList* i = new ValueList(); | |||||
| return *i; | |||||
| } | |||||
| ValueList::ValueList() {} | |||||
| ValueList::~ValueList() { clearSingletonInstance(); } | |||||
| void ValueList::addValue (LiveValueBase* v) | void ValueList::addValue (LiveValueBase* v) | ||||
| { | { | ||||
| @@ -194,7 +194,7 @@ namespace LiveConstantEditor | |||||
| ValueList(); | ValueList(); | ||||
| ~ValueList(); | ~ValueList(); | ||||
| static ValueList& getInstance(); | |||||
| juce_DeclareSingleton (ValueList, false) | |||||
| template <typename Type> | template <typename Type> | ||||
| LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue) | LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue) | ||||
| @@ -233,7 +233,7 @@ namespace LiveConstantEditor | |||||
| template <typename Type> | template <typename Type> | ||||
| inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue) | inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue) | ||||
| { | { | ||||
| return ValueList::getInstance().getValue (file, line, initialValue); | |||||
| return ValueList::getInstance()->getValue (file, line, initialValue); | |||||
| } | } | ||||
| inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue) | inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue) | ||||