| @@ -32,6 +32,7 @@ SynthesiserVoice::SynthesiserVoice() | |||
| currentPlayingMidiChannel (0), | |||
| noteOnTime (0), | |||
| keyIsDown (false), | |||
| sustainPedalDown (false), | |||
| sostenutoPedalDown (false) | |||
| { | |||
| } | |||
| @@ -296,6 +297,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice, | |||
| voice->currentlyPlayingSound = sound; | |||
| voice->keyIsDown = true; | |||
| voice->sostenutoPedalDown = false; | |||
| voice->sustainPedalDown = sustainPedalsDown[midiChannel]; | |||
| voice->startNote (midiNoteNumber, velocity, sound, | |||
| lastPitchWheelValues [midiChannel - 1]); | |||
| @@ -331,9 +333,11 @@ void Synthesiser::noteOff (const int midiChannel, | |||
| if (sound->appliesToNote (midiNoteNumber) | |||
| && sound->appliesToChannel (midiChannel)) | |||
| { | |||
| jassert (! voice->keyIsDown || voice->sustainPedalDown == sustainPedalsDown [midiChannel]); | |||
| voice->keyIsDown = false; | |||
| if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown)) | |||
| if (! (voice->sustainPedalDown || voice->sostenutoPedalDown)) | |||
| stopVoice (voice, velocity, allowTailOff); | |||
| } | |||
| } | |||
| @@ -427,6 +431,14 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) | |||
| if (isDown) | |||
| { | |||
| 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 | |||
| { | |||
| @@ -434,8 +446,13 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) | |||
| { | |||
| 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); | |||
| @@ -505,8 +522,13 @@ struct VoiceAgeSorter | |||
| SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| 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 | |||
| Array<SynthesiserVoice*> usableVoices; | |||
| @@ -516,24 +538,33 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| { | |||
| SynthesiserVoice* const voice = voices.getUnchecked (i); | |||
| jassert (voice->isVoiceActive()); // We wouldn't be here otherwise | |||
| if (voice->canPlaySound (soundToPlay)) | |||
| { | |||
| VoiceAgeSorter sorter; | |||
| 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(); | |||
| // 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) | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| @@ -547,7 +578,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| if (voice != bottom && voice != top && ! voice->isKeyDown() && ! voice->isSostenutoPedalDown()) | |||
| if (voice != low && voice != top && voice->isPlayingButReleased()) | |||
| return voice; | |||
| } | |||
| @@ -556,21 +587,25 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| if (voice != bottom && voice != top && ! voice->isKeyDown()) | |||
| if (voice != low && voice != top && ! voice->isKeyDown()) | |||
| 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) | |||
| { | |||
| SynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| if (voice != bottom && voice != top) | |||
| if (voice != low && voice != top) | |||
| 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; } | |||
| /** 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. */ | |||
| 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. */ | |||
| bool wasStartedBefore (const SynthesiserVoice& other) const noexcept; | |||
| @@ -244,7 +253,7 @@ private: | |||
| int currentlyPlayingNote, currentPlayingMidiChannel; | |||
| uint32 noteOnTime; | |||
| SynthesiserSound::Ptr currentlyPlayingSound; | |||
| bool keyIsDown, sostenutoPedalDown; | |||
| bool keyIsDown, sustainPedalDown, sostenutoPedalDown; | |||
| #if JUCE_CATCH_DEPRECATED_CODE_MISUSE | |||
| // Note the new parameters for this method. | |||
| @@ -486,14 +486,17 @@ public: | |||
| sampleRate = newSampleRate; | |||
| 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(); | |||
| inputChannelDataForCallback.clear(); | |||
| currentInputChans.clear(); | |||
| 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]) | |||
| { | |||
| @@ -505,14 +508,17 @@ public: | |||
| 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(); | |||
| outputChannelDataForCallback.clear(); | |||
| currentOutputChans.clear(); | |||
| 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]) | |||
| { | |||
| @@ -796,10 +802,10 @@ class ALSAAudioIODevice : public AudioIODevice | |||
| { | |||
| public: | |||
| ALSAAudioIODevice (const String& deviceName, | |||
| const String& typeName, | |||
| const String& deviceTypeName, | |||
| const String& inputDeviceID, | |||
| const String& outputDeviceID) | |||
| : AudioIODevice (deviceName, typeName), | |||
| : AudioIODevice (deviceName, deviceTypeName), | |||
| inputId (inputDeviceID), | |||
| outputId (outputDeviceID), | |||
| isOpen_ (false), | |||
| @@ -924,8 +930,8 @@ private: | |||
| class ALSAAudioIODeviceType : public AudioIODeviceType | |||
| { | |||
| public: | |||
| ALSAAudioIODeviceType (bool onlySoundcards, const String &typeName) | |||
| : AudioIODeviceType (typeName), | |||
| ALSAAudioIODeviceType (bool onlySoundcards, const String &deviceTypeName) | |||
| : AudioIODeviceType (deviceTypeName), | |||
| hasScanned (false), | |||
| listOnlySoundcards (onlySoundcards) | |||
| { | |||
| @@ -277,7 +277,7 @@ public: | |||
| 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) | |||
| { | |||
| @@ -45,6 +45,14 @@ namespace CoreMidiHelpers | |||
| #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) | |||
| { | |||
| String result; | |||
| @@ -116,7 +124,7 @@ namespace CoreMidiHelpers | |||
| 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) | |||
| { | |||
| @@ -133,7 +141,7 @@ namespace CoreMidiHelpers | |||
| || connObjectType == kMIDIObjectType_ExternalDestination) | |||
| { | |||
| // 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 | |||
| { | |||
| @@ -208,9 +216,9 @@ namespace CoreMidiHelpers | |||
| // correctly when called from the message thread! | |||
| 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; | |||
| @@ -220,12 +228,12 @@ namespace CoreMidiHelpers | |||
| class MidiPortAndEndpoint | |||
| { | |||
| public: | |||
| MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) | |||
| MidiPortAndEndpoint (MIDIPortRef p, MIDIEndpointRef ep) noexcept | |||
| : port (p), endPoint (ep) | |||
| { | |||
| } | |||
| ~MidiPortAndEndpoint() | |||
| ~MidiPortAndEndpoint() noexcept | |||
| { | |||
| if (port != 0) | |||
| MIDIPortDispose (port); | |||
| @@ -234,7 +242,7 @@ namespace CoreMidiHelpers | |||
| MIDIEndpointDispose (endPoint); | |||
| } | |||
| void send (const MIDIPacketList* const packets) | |||
| void send (const MIDIPacketList* const packets) noexcept | |||
| { | |||
| if (port != 0) | |||
| MIDISend (port, endPoint, packets); | |||
| @@ -302,7 +310,7 @@ namespace CoreMidiHelpers | |||
| 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); | |||
| CFStringRef pname; | |||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname))) | |||
| CoreMidiHelpers::ScopedCFString pname; | |||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &pname.cfString))) | |||
| { | |||
| MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | |||
| 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->internal = new CoreMidiHelpers::MidiPortAndEndpoint (port, endPoint); | |||
| } | |||
| CFRelease (pname); | |||
| } | |||
| } | |||
| @@ -339,20 +346,20 @@ MidiOutput* MidiOutput::openDevice (int index) | |||
| MidiOutput* MidiOutput::createNewDevice (const String& deviceName) | |||
| { | |||
| MidiOutput* mo = nullptr; | |||
| MIDIClientRef client = CoreMidiHelpers::getGlobalMidiClient(); | |||
| 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); | |||
| return mo; | |||
| } | |||
| CFRelease (name); | |||
| return mo; | |||
| return nullptr; | |||
| } | |||
| MidiOutput::~MidiOutput() | |||
| @@ -370,7 +377,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) | |||
| const MIDITimeStamp timeStamp = AudioGetCurrentHostTime(); | |||
| #endif | |||
| HeapBlock <MIDIPacketList> allocatedPackets; | |||
| HeapBlock<MIDIPacketList> allocatedPackets; | |||
| MIDIPacketList stackPacket; | |||
| MIDIPacketList* packetToSend = &stackPacket; | |||
| 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)) | |||
| { | |||
| CFStringRef name; | |||
| ScopedCFString name; | |||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name))) | |||
| if (CHECK_ERROR (MIDIObjectGetStringProperty (endPoint, kMIDIPropertyName, &name.cfString))) | |||
| { | |||
| if (MIDIClientRef client = getGlobalMidiClient()) | |||
| { | |||
| 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))) | |||
| { | |||
| @@ -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()) | |||
| { | |||
| ScopedPointer <MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||
| ScopedPointer<MidiPortAndCallback> mpc (new MidiPortAndCallback (*callback)); | |||
| mpc->active = false; | |||
| 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); | |||
| @@ -499,8 +505,6 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba | |||
| const ScopedLock sl (callbackLock); | |||
| activeCallbacks.add (mpc.release()); | |||
| } | |||
| CFRelease (name); | |||
| } | |||
| return mi; | |||
| @@ -341,10 +341,10 @@ namespace AiffFileHelpers | |||
| out.writeByte ((char) labelLength + 1); | |||
| out.write (label.toUTF8(), labelLength); | |||
| 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 | |||
| { | |||
| 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) | |||
| { | |||
| } | |||
| @@ -163,7 +163,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, | |||
| } | |||
| else | |||
| { | |||
| HeapBlock<int*> chans ((size_t) numTargetChannels); | |||
| HeapBlock<int*> chans ((size_t) numTargetChannels + 1); | |||
| 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 | |||
| { | |||
| ignoreUnused (e); | |||
| if (increment < 0) | |||
| { | |||
| ev.xbutton.button = Button5; | |||
| @@ -1633,7 +1635,7 @@ public: | |||
| void* data = nullptr; | |||
| 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.copyFrom (data, 0, bytes); | |||
| @@ -29,7 +29,7 @@ | |||
| struct NamedValueSet::NamedValue | |||
| { | |||
| 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) {} | |||
| #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 | |||
| bool NamedValueSet::set (Identifier name, var&& newValue) | |||
| bool NamedValueSet::set (const Identifier& name, var&& newValue) | |||
| { | |||
| if (var* const v = getVarPointer (name)) | |||
| { | |||
| @@ -154,7 +156,7 @@ bool NamedValueSet::set (Identifier name, var&& newValue) | |||
| } | |||
| #endif | |||
| bool NamedValueSet::set (Identifier name, const var& newValue) | |||
| bool NamedValueSet::set (const Identifier& name, const var& newValue) | |||
| { | |||
| if (var* const v = getVarPointer (name)) | |||
| { | |||
| @@ -78,14 +78,14 @@ public: | |||
| @returns true if a value was changed or added; false if the | |||
| 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 | |||
| /** Changes or adds a named value. | |||
| @returns true if a value was changed or added; false if the | |||
| value was already set the value passed-in. | |||
| */ | |||
| bool set (Identifier name, var&& newValue); | |||
| bool set (const Identifier& name, var&& newValue); | |||
| #endif | |||
| /** 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()) | |||
| return o->getProperty (propertyName); | |||
| @@ -589,7 +589,7 @@ const var& var::operator[] (const char* const propertyName) const | |||
| 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()) | |||
| return o->getProperties().getWithDefault (propertyName, defaultReturnValue); | |||
| @@ -602,7 +602,7 @@ var::NativeFunction var::getNativeFunction() const | |||
| 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()) | |||
| 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(); | |||
| } | |||
| var var::call (const Identifier method) const | |||
| var var::call (const Identifier& method) const | |||
| { | |||
| 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); | |||
| } | |||
| 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 }; | |||
| 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 }; | |||
| 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 }; | |||
| 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 }; | |||
| return invoke (method, args, 5); | |||
| @@ -62,7 +62,6 @@ public: | |||
| }; | |||
| typedef var (*NativeFunction) (const NativeFunctionArgs&); | |||
| typedef Identifier identifier; | |||
| //============================================================================== | |||
| /** Creates a void variant. */ | |||
| @@ -242,27 +241,27 @@ public: | |||
| //============================================================================== | |||
| /** 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. */ | |||
| const var& operator[] (const char* propertyName) const; | |||
| /** If this variant is an object, this returns one of its properties, or a default | |||
| 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. */ | |||
| var call (Identifier method) const; | |||
| var call (const Identifier& method) const; | |||
| /** 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| NativeFunction getNativeFunction() const; | |||
| @@ -916,6 +916,11 @@ public: | |||
| const File temp (File::getSpecialLocation (File::tempDirectory)); | |||
| expect (! File::nonexistent.exists()); | |||
| expect (! File::nonexistent.existsAsFile()); | |||
| expect (! File::nonexistent.isDirectory()); | |||
| #if ! JUCE_WINDOWS | |||
| expect (File("/").isDirectory()); | |||
| #endif | |||
| expect (home.isDirectory()); | |||
| expect (home.exists()); | |||
| 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 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 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 | |||
| @@ -136,7 +136,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| ReferenceCountedObjectPtr<RootObject> root; | |||
| 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()) | |||
| { | |||
| @@ -170,7 +170,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| 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()) | |||
| return getPropertyPointer (cls, propName); | |||
| @@ -178,7 +178,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| return nullptr; | |||
| } | |||
| var findSymbolInParentScopes (Identifier name) const | |||
| var findSymbolInParentScopes (const Identifier& name) const | |||
| { | |||
| if (const var* v = getPropertyPointer (scope, name)) | |||
| return *v; | |||
| @@ -187,7 +187,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| : 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(); | |||
| @@ -352,7 +352,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| 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); } | |||
| @@ -369,7 +369,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
| 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 | |||
| { | |||
| @@ -1670,7 +1670,7 @@ JavascriptEngine::~JavascriptEngine() {} | |||
| 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); | |||
| } | |||
| @@ -1706,7 +1706,7 @@ var JavascriptEngine::evaluate (const String& code, Result* result) | |||
| 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()); | |||
| @@ -78,7 +78,7 @@ public: | |||
| The function arguments are passed in the same format as used by native | |||
| methods in the var class. | |||
| */ | |||
| var callFunction (Identifier function, | |||
| var callFunction (const Identifier& function, | |||
| const var::NativeFunctionArgs& args, | |||
| Result* errorMessage = nullptr); | |||
| @@ -87,7 +87,7 @@ public: | |||
| engine until the engine is deleted. The name must be a simple JS identifier, | |||
| 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 | |||
| to run before timing-out and failing. | |||
| @@ -45,6 +45,16 @@ struct ContainerDeletePolicy | |||
| { | |||
| 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; | |||
| } | |||
| }; | |||
| @@ -50,7 +50,7 @@ inline void deleteAndZero (Type& pointer) { delete poi | |||
| a specific number of bytes, | |||
| */ | |||
| 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. | |||
| 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. | |||
| */ | |||
| 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 | |||
| @@ -94,13 +94,12 @@ public: | |||
| */ | |||
| 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. | |||
| @@ -145,7 +144,22 @@ private: | |||
| 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; | |||
| 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 | |||
| @@ -248,6 +248,9 @@ public: | |||
| /** 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 | |||
| the parameters, otherwise it'll encode them into the | |||
| 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 | |||
| 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 usePostCommand whether to use a POST command to get the data (uses | |||
| 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 | |||
| 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 | |||
| a GET command if this is false) | |||
| @see readEntireBinaryStream, readEntireXmlStream | |||
| @@ -316,6 +325,9 @@ public: | |||
| When it returns a valid XmlElement object, the caller is responsibile for deleting | |||
| 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 | |||
| 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::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; | |||
| return *this; | |||
| @@ -68,16 +68,24 @@ public: | |||
| Identifier (const Identifier& other) noexcept; | |||
| /** 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 */ | |||
| ~Identifier() noexcept; | |||
| /** 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. */ | |||
| 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. */ | |||
| inline bool operator== (StringRef other) const noexcept { return name == other; } | |||
| @@ -89,12 +89,12 @@ public: | |||
| */ | |||
| 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. | |||
| */ | |||
| 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. | |||
| */ | |||
| String (const wchar_t* text, size_t maxChars); | |||
| @@ -27,7 +27,7 @@ class ValueTree::SharedObject : public ReferenceCountedObject | |||
| public: | |||
| typedef ReferenceCountedObjectPtr<SharedObject> Ptr; | |||
| explicit SharedObject (Identifier t) noexcept | |||
| explicit SharedObject (const Identifier& t) noexcept | |||
| : type (t), parent (nullptr) | |||
| { | |||
| } | |||
| @@ -126,7 +126,7 @@ public: | |||
| } | |||
| } | |||
| void sendPropertyChangeMessage (const Identifier property) | |||
| void sendPropertyChangeMessage (const Identifier& property) | |||
| { | |||
| ValueTree tree (this); | |||
| @@ -169,7 +169,7 @@ public: | |||
| 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) | |||
| { | |||
| @@ -190,12 +190,12 @@ public: | |||
| } | |||
| } | |||
| bool hasProperty (const Identifier name) const noexcept | |||
| bool hasProperty (const Identifier& name) const noexcept | |||
| { | |||
| return properties.contains (name); | |||
| } | |||
| void removeProperty (const Identifier name, UndoManager* const undoManager) | |||
| void removeProperty (const Identifier& name, UndoManager* const undoManager) | |||
| { | |||
| if (undoManager == nullptr) | |||
| { | |||
| @@ -238,7 +238,7 @@ public: | |||
| 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) | |||
| { | |||
| @@ -250,7 +250,7 @@ public: | |||
| return ValueTree(); | |||
| } | |||
| ValueTree getOrCreateChildWithName (const Identifier typeToMatch, UndoManager* undoManager) | |||
| ValueTree getOrCreateChildWithName (const Identifier& typeToMatch, UndoManager* undoManager) | |||
| { | |||
| 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) | |||
| { | |||
| @@ -458,7 +458,7 @@ public: | |||
| class SetPropertyAction : public UndoableAction | |||
| { | |||
| 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) | |||
| : target (so), name (propertyName), newValue (newVal), oldValue (oldVal), | |||
| isAddingNewProperty (isAdding), isDeletingProperty (isDeleting) | |||
| @@ -629,7 +629,7 @@ ValueTree::ValueTree() noexcept | |||
| 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! | |||
| } | |||
| @@ -702,7 +702,7 @@ ValueTree ValueTree::createCopy() const | |||
| 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; | |||
| } | |||
| @@ -727,24 +727,23 @@ ValueTree ValueTree::getSibling (const int delta) const | |||
| 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]; | |||
| } | |||
| const var& ValueTree::getProperty (const Identifier name) const | |||
| const var& ValueTree::getProperty (const Identifier& name) const | |||
| { | |||
| 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 | |||
| : 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 (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; | |||
| } | |||
| bool ValueTree::hasProperty (const Identifier name) const | |||
| bool ValueTree::hasProperty (const Identifier& name) const | |||
| { | |||
| 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) | |||
| object->removeProperty (name, undoManager); | |||
| @@ -803,7 +802,7 @@ class ValueTreePropertyValueSource : public Value::ValueSource, | |||
| private ValueTree::Listener | |||
| { | |||
| 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.addListener (this); | |||
| @@ -836,7 +835,7 @@ private: | |||
| 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)); | |||
| } | |||
| @@ -853,17 +852,17 @@ ValueTree ValueTree::getChild (int index) const | |||
| : 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(); | |||
| } | |||
| ValueTree ValueTree::getOrCreateChildWithName (const Identifier type, UndoManager* undoManager) | |||
| ValueTree ValueTree::getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager) | |||
| { | |||
| 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(); | |||
| } | |||
| @@ -945,7 +944,7 @@ void ValueTree::removeListener (Listener* listener) | |||
| object->valueTreesWithListeners.removeValue (this); | |||
| } | |||
| void ValueTree::sendPropertyChangeMessage (const Identifier property) | |||
| void ValueTree::sendPropertyChangeMessage (const Identifier& property) | |||
| { | |||
| if (object != nullptr) | |||
| object->sendPropertyChangeMessage (property); | |||
| @@ -79,7 +79,7 @@ public: | |||
| Like an XmlElement, each ValueTree node has a type, which you can access with | |||
| getType() and hasType(). | |||
| */ | |||
| explicit ValueTree (Identifier type); | |||
| explicit ValueTree (const Identifier& type); | |||
| /** Creates a reference to another ValueTree. */ | |||
| ValueTree (const ValueTree&); | |||
| @@ -134,7 +134,7 @@ public: | |||
| /** Returns true if the node has this type. | |||
| The comparison is case-sensitive. | |||
| */ | |||
| bool hasType (const Identifier typeName) const; | |||
| bool hasType (const Identifier& typeName) const; | |||
| //============================================================================== | |||
| /** Returns the value of a named property. | |||
| @@ -142,21 +142,21 @@ public: | |||
| You can also use operator[] to get a property. | |||
| @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. | |||
| 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. | |||
| @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. | |||
| If no such property has been set, this will return a void variant. This is the same as | |||
| calling getProperty(). | |||
| @see getProperty | |||
| */ | |||
| const var& operator[] (const Identifier name) const; | |||
| const var& operator[] (const Identifier& name) const; | |||
| /** Changes a named property of the node. | |||
| The name identifier must not be an empty string. | |||
| @@ -165,16 +165,16 @@ public: | |||
| @see var, getProperty, removeProperty | |||
| @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. */ | |||
| bool hasProperty (const Identifier name) const; | |||
| bool hasProperty (const Identifier& name) const; | |||
| /** Removes a property from the node. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeProperty (const Identifier name, UndoManager* undoManager); | |||
| void removeProperty (const Identifier& name, UndoManager* undoManager); | |||
| /** Removes all properties from the node. | |||
| 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 | |||
| 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. | |||
| 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). | |||
| @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 | |||
| a child with this name if there wasn't already one there. | |||
| @@ -232,7 +232,7 @@ public: | |||
| the method on is itself invalid. | |||
| @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. | |||
| @@ -242,7 +242,7 @@ public: | |||
| If no such node is found, it'll return an invalid node. (See isValid() to find out | |||
| whether a node is valid). | |||
| */ | |||
| ValueTree getChildWithProperty (const Identifier propertyName, const var& propertyValue) const; | |||
| ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; | |||
| /** Adds a child to this node. | |||
| @@ -453,7 +453,7 @@ public: | |||
| /** Causes a property-change callback to be triggered for the specified property, | |||
| 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. | |||
| @@ -32,8 +32,8 @@ namespace | |||
| jassert ((int) x >= -maxVal && (int) x <= 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 | |||
| 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 | |||
| { | |||
| jassert (r.getWidth() >= 0.0f && r.getHeight() >= 0.0f); | |||
| RectangleList<float> rects; | |||
| rects.addWithoutMerging (r.removeFromTop (lineThickness)); | |||
| rects.addWithoutMerging (r.removeFromBottom (lineThickness)); | |||
| @@ -52,21 +52,21 @@ public: | |||
| } | |||
| /** 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), | |||
| w (width), h (height) | |||
| { | |||
| } | |||
| /** 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) | |||
| { | |||
| } | |||
| /** 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), | |||
| jmin (corner1.y, corner2.y)), | |||
| 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 | |||
| 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); | |||
| } | |||
| @@ -134,17 +134,17 @@ public: | |||
| /** Returns the aspect ratio of the rectangle's width / height. | |||
| If widthOverHeight is true, it returns width / height; if widthOverHeight is false, | |||
| 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. */ | |||
| inline Point<ValueType> getPosition() const noexcept { return pos; } | |||
| /** 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). */ | |||
| 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. */ | |||
| Point<ValueType> getTopLeft() const noexcept { return pos; } | |||
| @@ -158,62 +158,75 @@ public: | |||
| /** Returns the rectangle's bottom-right position as a Point. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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 */ | |||
| 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 */ | |||
| inline void setY (const ValueType newY) noexcept { pos.y = newY; } | |||
| inline void setY (ValueType newY) noexcept { pos.y = newY; } | |||
| /** 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 */ | |||
| 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). */ | |||
| 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). */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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). */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. */ | |||
| 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. | |||
| 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. */ | |||
| void translate (const ValueType deltaX, | |||
| const ValueType deltaY) noexcept | |||
| void translate (ValueType deltaX, | |||
| ValueType deltaY) noexcept | |||
| { | |||
| pos.x += deltaX; | |||
| pos.y += deltaY; | |||
| } | |||
| /** 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); | |||
| } | |||
| /** 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); | |||
| } | |||
| /** Moves this rectangle by a given amount. */ | |||
| Rectangle& operator+= (const Point<ValueType> deltaPosition) noexcept | |||
| Rectangle& operator+= (Point<ValueType> deltaPosition) noexcept | |||
| { | |||
| pos += deltaPosition; | |||
| return *this; | |||
| } | |||
| /** 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); | |||
| } | |||
| /** Moves this rectangle by a given amount. */ | |||
| Rectangle& operator-= (const Point<ValueType> deltaPosition) noexcept | |||
| Rectangle& operator-= (Point<ValueType> deltaPosition) noexcept | |||
| { | |||
| pos -= deltaPosition; | |||
| return *this; | |||
| @@ -396,8 +409,8 @@ public: | |||
| Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). | |||
| @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 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). | |||
| @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 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). | |||
| @see expand, reduce, reduced | |||
| */ | |||
| Rectangle expanded (const ValueType delta) const noexcept | |||
| Rectangle expanded (ValueType delta) const noexcept | |||
| { | |||
| return expanded (delta, delta); | |||
| } | |||
| @@ -432,8 +445,8 @@ public: | |||
| Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | |||
| @see reduced, expand, expanded | |||
| */ | |||
| void reduce (const ValueType deltaX, | |||
| const ValueType deltaY) noexcept | |||
| void reduce (ValueType deltaX, | |||
| ValueType deltaY) noexcept | |||
| { | |||
| expand (-deltaX, -deltaY); | |||
| } | |||
| @@ -443,8 +456,8 @@ public: | |||
| Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). | |||
| @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); | |||
| } | |||
| @@ -454,7 +467,7 @@ public: | |||
| Effectively, the rectangle returned is (x + delta, y + delta, w - delta * 2, h - delta * 2). | |||
| @see reduce, expand, expanded | |||
| */ | |||
| Rectangle reduced (const ValueType delta) const noexcept | |||
| Rectangle reduced (ValueType delta) const noexcept | |||
| { | |||
| return reduced (delta, delta); | |||
| } | |||
| @@ -468,7 +481,7 @@ public: | |||
| If amountToRemove is greater than the height of this rectangle, it'll be clipped to | |||
| that value. | |||
| */ | |||
| Rectangle removeFromTop (const ValueType amountToRemove) noexcept | |||
| Rectangle removeFromTop (ValueType amountToRemove) noexcept | |||
| { | |||
| const Rectangle r (pos.x, pos.y, w, jmin (amountToRemove, 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 | |||
| that value. | |||
| */ | |||
| Rectangle removeFromLeft (const ValueType amountToRemove) noexcept | |||
| Rectangle removeFromLeft (ValueType amountToRemove) noexcept | |||
| { | |||
| const Rectangle r (pos.x, pos.y, jmin (amountToRemove, w), h); | |||
| 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; } | |||
| /** 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; | |||
| } | |||
| /** 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; | |||
| } | |||
| @@ -552,7 +565,7 @@ public: | |||
| } | |||
| /** 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), | |||
| jlimit (pos.y, pos.y + h, point.y)); | |||
| @@ -59,6 +59,7 @@ void DrawableButton::setImages (const Drawable* normal, | |||
| overImageOn = copyDrawableIfNotNull (overOn); | |||
| downImageOn = copyDrawableIfNotNull (downOn); | |||
| disabledImageOn = copyDrawableIfNotNull (disabledOn); | |||
| currentImage = nullptr; | |||
| buttonStateChanged(); | |||
| } | |||
| @@ -1153,12 +1153,15 @@ void Component::setBounds (const int x, const int y, int w, int h) | |||
| 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.isResizeCallbackPending = false; | |||
| sendMovedResizedMessages (wasMoved, wasResized); | |||
| } | |||
| } | |||
| @@ -812,7 +812,7 @@ public: | |||
| 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 | |||
| mouse-clicks within a user-defined area. | |||
| @@ -387,7 +387,7 @@ void FileBrowserComponent::fileDoubleClicked (const File& f) | |||
| { | |||
| setRoot (f); | |||
| if ((flags & canSelectDirectories) != 0) | |||
| if ((flags & canSelectDirectories) != 0 && (flags & doNotClearFileNameOnRootChange) == 0) | |||
| filenameBox.setText (String::empty); | |||
| } | |||
| else | |||
| @@ -432,7 +432,9 @@ void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&) | |||
| { | |||
| setRoot (f); | |||
| chosenFiles.clear(); | |||
| filenameBox.setText (String::empty); | |||
| if ((flags & doNotClearFileNameOnRootChange) == 0) | |||
| filenameBox.setText (String()); | |||
| } | |||
| else | |||
| { | |||
| @@ -51,18 +51,19 @@ public: | |||
| */ | |||
| 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) | |||
| : Component (name), | |||
| customScrollBarThickness(false), | |||
| scrollBarThickness (0), | |||
| singleStepX (16), | |||
| singleStepY (16), | |||
| showHScrollbar (true), | |||
| showVScrollbar (true), | |||
| deleteContent (true), | |||
| customScrollBarThickness (false), | |||
| allowScrollingWithoutScrollbarV (false), | |||
| allowScrollingWithoutScrollbarH (false), | |||
| verticalScrollBar (true), | |||
| @@ -55,7 +55,6 @@ Viewport::Viewport (const String& name) | |||
| Viewport::~Viewport() | |||
| { | |||
| deleteContentComp(); | |||
| mouseWheelTimer = nullptr; | |||
| } | |||
| //============================================================================== | |||
| @@ -382,30 +381,6 @@ static int rescaleMouseWheelDistance (float distance, int singleStepSize) noexce | |||
| : 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) | |||
| { | |||
| 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 (mouseWheelTimer == nullptr) | |||
| mouseWheelTimer = new MouseWheelTimer (*this); | |||
| mouseWheelTimer->startTimer (300); | |||
| setViewPosition (pos); | |||
| return true; | |||
| } | |||
| @@ -263,15 +263,13 @@ private: | |||
| //============================================================================== | |||
| WeakReference<Component> contentComp; | |||
| Rectangle<int> lastVisibleArea; | |||
| bool customScrollBarThickness; | |||
| int scrollBarThickness; | |||
| int singleStepX, singleStepY; | |||
| bool showHScrollbar, showVScrollbar, deleteContent; | |||
| bool customScrollBarThickness; | |||
| bool allowScrollingWithoutScrollbarV, allowScrollingWithoutScrollbarH; | |||
| Component contentHolder; | |||
| ScrollBar verticalScrollBar, horizontalScrollBar; | |||
| struct MouseWheelTimer; | |||
| ScopedPointer<Timer> mouseWheelTimer; | |||
| Point<int> viewportPosToCompPos (Point<int>) const; | |||
| @@ -43,7 +43,7 @@ public: | |||
| imageOffset (offset), | |||
| hasCheckedForExternalDrag (false) | |||
| { | |||
| setSize (im.getWidth(), im.getHeight()); | |||
| updateSize(); | |||
| if (mouseDragSource == nullptr) | |||
| mouseDragSource = sourceComponent; | |||
| @@ -160,6 +160,13 @@ public: | |||
| forceMouseCursorUpdate(); | |||
| } | |||
| void updateImage (const Image& newImage) | |||
| { | |||
| image = newImage; | |||
| updateSize(); | |||
| repaint(); | |||
| } | |||
| void timerCallback() override | |||
| { | |||
| forceMouseCursorUpdate(); | |||
| @@ -207,6 +214,11 @@ private: | |||
| bool hasCheckedForExternalDrag; | |||
| Time lastTimeOverTarget; | |||
| void updateSize() | |||
| { | |||
| setSize (image.getWidth(), image.getHeight()); | |||
| } | |||
| void forceMouseCursorUpdate() | |||
| { | |||
| Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); | |||
| @@ -472,6 +484,12 @@ var DragAndDropContainer::getCurrentDragDescription() const | |||
| : var(); | |||
| } | |||
| void DragAndDropContainer::setCurrentDragImage (const Image& newImage) | |||
| { | |||
| if (dragImageComponent != nullptr) | |||
| dragImageComponent->updateImage (newImage); | |||
| } | |||
| DragAndDropContainer* DragAndDropContainer::findParentDragContainerFor (Component* c) | |||
| { | |||
| return c != nullptr ? c->findParentComponentOfClass<DragAndDropContainer>() : nullptr; | |||
| @@ -102,6 +102,9 @@ public: | |||
| */ | |||
| 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. | |||
| 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. */ | |||
| 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) | |||
| { | |||
| Desktop::getInstance().incrementMouseWheelCounter(); | |||
| 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, | |||
| @@ -467,7 +474,7 @@ public: | |||
| bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | |||
| private: | |||
| WeakReference<Component> componentUnderMouse; | |||
| WeakReference<Component> componentUnderMouse, lastNonInertialWheelTarget; | |||
| ComponentPeer* lastPeer; | |||
| void* currentCursorHandle; | |||
| @@ -512,6 +519,7 @@ private: | |||
| mouseDowns[0].peerID = 0; | |||
| mouseMovedSignificantlySincePressed = false; | |||
| lastNonInertialWheelTarget = nullptr; | |||
| } | |||
| void registerMouseDrag (Point<float> screenPos) noexcept | |||
| @@ -112,7 +112,8 @@ public: | |||
| : ComponentPeer (comp, windowStyleFlags), | |||
| usingAndroidGraphics (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, | |||
| // which will fail if the peer is only half-constructed. | |||
| @@ -189,8 +190,10 @@ public: | |||
| 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()) | |||
| { | |||
| fullScreen = isNowFullScreen; | |||
| @@ -224,7 +227,7 @@ public: | |||
| return Rectangle<int> (view.callIntMethod (ComponentPeerView.getLeft), | |||
| view.callIntMethod (ComponentPeerView.getTop), | |||
| view.callIntMethod (ComponentPeerView.getWidth), | |||
| view.callIntMethod (ComponentPeerView.getHeight)); | |||
| view.callIntMethod (ComponentPeerView.getHeight)) / scale; | |||
| } | |||
| void handleScreenSizeChange() | |||
| @@ -238,7 +241,7 @@ public: | |||
| Point<int> getScreenPosition() const | |||
| { | |||
| return Point<int> (view.callIntMethod (ComponentPeerView.getLeft), | |||
| view.callIntMethod (ComponentPeerView.getTop)); | |||
| view.callIntMethod (ComponentPeerView.getTop)) / scale; | |||
| } | |||
| Point<float> localToGlobal (Point<float> relativePosition) override | |||
| @@ -291,7 +294,8 @@ public: | |||
| return isPositiveAndBelow (localPos.x, component.getWidth()) | |||
| && isPositiveAndBelow (localPos.y, component.getHeight()) | |||
| && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, | |||
| localPos.x, localPos.y)); | |||
| localPos.x * scale, | |||
| localPos.y * scale)); | |||
| } | |||
| 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; | |||
| // 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); | |||
| if (isValidPeer (this)) | |||
| handleMouseDragCallback (index, pos, time); | |||
| handleMouseDragCallback (index, sysPos, time); | |||
| } | |||
| void handleMouseDragCallback (int index, Point<float> pos, int64 time) | |||
| { | |||
| pos /= scale; | |||
| lastMousePos = pos; | |||
| jassert (index < 64); | |||
| @@ -346,6 +352,7 @@ public: | |||
| void handleMouseUpCallback (int index, Point<float> pos, int64 time) | |||
| { | |||
| pos /= scale; | |||
| lastMousePos = pos; | |||
| jassert (index < 64); | |||
| @@ -441,6 +448,7 @@ public: | |||
| { | |||
| LowLevelGraphicsSoftwareRenderer g (temp); | |||
| g.setOrigin (-clip.getPosition()); | |||
| g.addTransform (AffineTransform::scale (scale)); | |||
| 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()) | |||
| { | |||
| view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); | |||
| @@ -507,6 +517,7 @@ private: | |||
| GlobalRef buffer; | |||
| bool usingAndroidGraphics, fullScreen; | |||
| int sizeAllocated; | |||
| float scale; | |||
| class PreallocatedImage : public ImagePixelData | |||
| { | |||
| @@ -723,11 +734,12 @@ bool juce_areThereAnyAlwaysOnTopWindows() | |||
| void Desktop::Displays::findDisplays (float masterScale) | |||
| { | |||
| Display d; | |||
| d.userArea = d.totalArea = Rectangle<int> (android.screenWidth, | |||
| android.screenHeight) / masterScale; | |||
| d.isMain = true; | |||
| d.scale = masterScale; | |||
| 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); | |||
| } | |||
| @@ -131,11 +131,11 @@ static void addZenityArgs (StringArray& args, String& separator, | |||
| 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()) | |||
| @@ -978,9 +978,9 @@ private: | |||
| //============================================================================== | |||
| #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 | |||
| { | |||
| @@ -1062,9 +1062,9 @@ 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) | |||
| { | |||
| @@ -2209,6 +2209,7 @@ public: | |||
| wheel.deltaY = amount; | |||
| wheel.isReversed = false; | |||
| wheel.isSmooth = false; | |||
| wheel.isInertial = false; | |||
| handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel); | |||
| } | |||
| @@ -3723,12 +3724,45 @@ void Desktop::Displays::findDisplays (float 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) | |||
| { | |||
| // don't add the main display a second time | |||
| if (i == mainDisplayIdx) | |||
| continue; | |||
| const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (i); | |||
| Desktop::Displays::Display d; | |||
| d.isMain = info.isMain; | |||
| d.isMain = false; | |||
| d.scale = masterScale * info.scale; | |||
| 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 | |||
| { | |||
| 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) | |||
| @@ -102,9 +130,10 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||
| case CopyingCursor: | |||
| { | |||
| #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; | |||
| #endif | |||
| c = [NSCursor dragCopyCursor]; // added in 10.6 | |||
| break; | |||
| } | |||
| @@ -112,10 +141,14 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||
| case UpDownResizeCursor: | |||
| case TopEdgeResizeCursor: | |||
| 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: | |||
| if (void* m = MouseCursorHelpers::fromWebKitFile ("eastWestResizeCursor.png", 0.5f, 0.5f)) | |||
| if (void* m = MouseCursorHelpers::fromHIServices ("resizeeastwest")) | |||
| return m; | |||
| c = [NSCursor resizeLeftRightCursor]; | |||
| @@ -123,14 +156,14 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||
| case TopLeftCornerResizeCursor: | |||
| case BottomRightCornerResizeCursor: | |||
| return MouseCursorHelpers::fromWebKitFile ("northWestSouthEastResizeCursor.png", 0.5f, 0.5f); | |||
| return MouseCursorHelpers::fromHIServices ("resizenorthwestsoutheast"); | |||
| case TopRightCornerResizeCursor: | |||
| case BottomLeftCornerResizeCursor: | |||
| return MouseCursorHelpers::fromWebKitFile ("northEastSouthWestResizeCursor.png", 0.5f, 0.5f); | |||
| return MouseCursorHelpers::fromHIServices ("resizenortheastsouthwest"); | |||
| case UpDownLeftRightResizeCursor: | |||
| return MouseCursorHelpers::fromWebKitFile ("moveCursor.png", 0.5f, 0.5f); | |||
| return MouseCursorHelpers::fromHIServices ("move"); | |||
| default: | |||
| jassertfalse; | |||
| @@ -497,10 +497,7 @@ public: | |||
| 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) | |||
| { | |||
| @@ -514,6 +511,10 @@ public: | |||
| relativeTo: [otherPeer->window windowNumber]]; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| jassertfalse; // wrong type of window? | |||
| } | |||
| } | |||
| void setIcon (const Image&) override | |||
| @@ -620,6 +621,7 @@ public: | |||
| wheel.deltaY = 0; | |||
| wheel.isReversed = false; | |||
| wheel.isSmooth = false; | |||
| wheel.isInertial = false; | |||
| #if ! JUCE_PPC | |||
| @try | |||
| @@ -628,6 +630,8 @@ public: | |||
| if ([ev respondsToSelector: @selector (isDirectionInvertedFromDevice)]) | |||
| wheel.isReversed = [ev isDirectionInvertedFromDevice]; | |||
| wheel.isInertial = ([ev momentumPhase] != NSEventPhaseNone); | |||
| if ([ev respondsToSelector: @selector (hasPreciseScrollingDeltas)]) | |||
| { | |||
| if ([ev hasPreciseScrollingDeltas]) | |||
| @@ -218,6 +218,8 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
| info.customComponent->enterModalState(); | |||
| } | |||
| const StringRef separatorTokens (";,|"); | |||
| const size_t filterSpaceNumChars = 2048; | |||
| HeapBlock<WCHAR> filters; | |||
| filters.calloc (filterSpaceNumChars); | |||
| @@ -225,6 +227,10 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
| filter.copyToUTF16 (filters + (bytesWritten / sizeof (WCHAR)), | |||
| ((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 }; | |||
| String localPath (info.initialPath); | |||
| @@ -249,7 +255,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
| if (isSaveDialogue) | |||
| { | |||
| StringArray tokens; | |||
| tokens.addTokens (filter, ";,", "\"'"); | |||
| tokens.addTokens (filter, separatorTokens, "\"'"); | |||
| tokens.trim(); | |||
| tokens.removeEmptyStrings(); | |||
| @@ -1820,6 +1820,7 @@ private: | |||
| wheel.deltaY = isVertical ? amount / 256.0f : 0.0f; | |||
| wheel.isReversed = false; | |||
| wheel.isSmooth = false; | |||
| wheel.isInertial = false; | |||
| Point<float> localPos; | |||
| if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) | |||
| @@ -2968,24 +2969,27 @@ bool KeyPress::isKeyCurrentlyDown (const int 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); | |||
| } | |||
| @@ -32,13 +32,10 @@ class AllComponentRepainter : private Timer, | |||
| private DeletedAtShutdown | |||
| { | |||
| public: | |||
| AllComponentRepainter() {} | |||
| AllComponentRepainter() {} | |||
| ~AllComponentRepainter() { clearSingletonInstance(); } | |||
| static AllComponentRepainter& getInstance() | |||
| { | |||
| static AllComponentRepainter* instance = new AllComponentRepainter(); | |||
| return *instance; | |||
| } | |||
| juce_DeclareSingleton (AllComponentRepainter, false) | |||
| void trigger() | |||
| { | |||
| @@ -51,26 +48,45 @@ private: | |||
| { | |||
| stopTimer(); | |||
| Array<Component*> alreadyDone; | |||
| for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;) | |||
| 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->resized(); | |||
| 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) | |||
| { | |||
| @@ -175,7 +191,7 @@ void LivePropertyEditorBase::applyNewValue (const String& s) | |||
| selectOriginalValue(); | |||
| valueEditor.setText (s, dontSendNotification); | |||
| AllComponentRepainter::getInstance().trigger(); | |||
| AllComponentRepainter::getInstance()->trigger(); | |||
| } | |||
| 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) | |||
| { | |||
| @@ -194,7 +194,7 @@ namespace LiveConstantEditor | |||
| ValueList(); | |||
| ~ValueList(); | |||
| static ValueList& getInstance(); | |||
| juce_DeclareSingleton (ValueList, false) | |||
| template <typename Type> | |||
| LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue) | |||
| @@ -233,7 +233,7 @@ namespace LiveConstantEditor | |||
| template <typename Type> | |||
| 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) | |||