| @@ -142,18 +142,12 @@ const ModuleDescription* ModuleList::getModuleWithID (const String& moduleID) co | |||
| return nullptr; | |||
| } | |||
| struct ModuleSorter | |||
| { | |||
| static int compareElements (const ModuleDescription* m1, const ModuleDescription* m2) | |||
| { | |||
| return m1->getID().compareIgnoreCase (m2->getID()); | |||
| } | |||
| }; | |||
| void ModuleList::sort() | |||
| { | |||
| ModuleSorter sorter; | |||
| modules.sort (sorter); | |||
| std::sort (modules.begin(), modules.end(), [] (const ModuleDescription* m1, const ModuleDescription* m2) | |||
| { | |||
| return m1->getID().compareIgnoreCase (m2->getID()) < 0; | |||
| }); | |||
| } | |||
| StringArray ModuleList::getIDs() const | |||
| @@ -131,23 +131,6 @@ namespace MidiFileHelpers | |||
| return correctedTime + (time - lastTime) * secsPerTick; | |||
| } | |||
| // a comparator that puts all the note-offs before note-ons that have the same time | |||
| struct Sorter | |||
| { | |||
| static int compareElements (const MidiMessageSequence::MidiEventHolder* const first, | |||
| const MidiMessageSequence::MidiEventHolder* const second) noexcept | |||
| { | |||
| const double diff = (first->message.getTimeStamp() - second->message.getTimeStamp()); | |||
| if (diff > 0) return 1; | |||
| if (diff < 0) return -1; | |||
| if (first->message.isNoteOff() && second->message.isNoteOn()) return -1; | |||
| if (first->message.isNoteOn() && second->message.isNoteOff()) return 1; | |||
| return 0; | |||
| } | |||
| }; | |||
| template <typename MethodType> | |||
| static void findAllMatchingEvents (const OwnedArray<MidiMessageSequence>& tracks, | |||
| MidiMessageSequence& results, | |||
| @@ -335,9 +318,19 @@ void MidiFile::readNextTrack (const uint8* data, int size) | |||
| lastStatusByte = firstByte; | |||
| } | |||
| // use a sort that puts all the note-offs before note-ons that have the same time | |||
| MidiFileHelpers::Sorter sorter; | |||
| result.list.sort (sorter, true); | |||
| // sort so that we put all the note-offs before note-ons that have the same time | |||
| std::stable_sort (result.list.begin(), result.list.end(), | |||
| [] (const MidiMessageSequence::MidiEventHolder* a, | |||
| const MidiMessageSequence::MidiEventHolder* b) | |||
| { | |||
| auto t1 = a->message.getTimeStamp(); | |||
| auto t2 = b->message.getTimeStamp(); | |||
| if (t1 < t2) return true; | |||
| if (t2 < t1) return false; | |||
| return a->message.isNoteOff() && b->message.isNoteOn(); | |||
| }); | |||
| addTrack (result); | |||
| tracks.getLast()->updateMatchedPairs(); | |||
| @@ -204,20 +204,10 @@ void MidiMessageSequence::addSequence (const MidiMessageSequence& other, | |||
| sort(); | |||
| } | |||
| struct MidiMessageSequenceSorter | |||
| { | |||
| static int compareElements (const MidiMessageSequence::MidiEventHolder* first, | |||
| const MidiMessageSequence::MidiEventHolder* second) noexcept | |||
| { | |||
| auto diff = first->message.getTimeStamp() - second->message.getTimeStamp(); | |||
| return (diff > 0) - (diff < 0); | |||
| } | |||
| }; | |||
| void MidiMessageSequence::sort() noexcept | |||
| { | |||
| MidiMessageSequenceSorter sorter; | |||
| list.sort (sorter, true); | |||
| std::stable_sort (list.begin(), list.end(), | |||
| [] (const MidiEventHolder* a, const MidiEventHolder* b) { return a->message.getTimeStamp() < b->message.getTimeStamp(); }); | |||
| } | |||
| void MidiMessageSequence::updateMatchedPairs() noexcept | |||
| @@ -179,14 +179,6 @@ MPESynthesiserVoice* MPESynthesiser::findFreeVoice (MPENote noteToFindVoiceFor, | |||
| return nullptr; | |||
| } | |||
| struct MPEVoiceAgeSorter | |||
| { | |||
| static int compareElements (MPESynthesiserVoice* v1, MPESynthesiserVoice* v2) noexcept | |||
| { | |||
| return v1->wasStartedBefore (*v2) ? -1 : (v2->wasStartedBefore (*v1) ? 1 : 0); | |||
| } | |||
| }; | |||
| MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceFor) const | |||
| { | |||
| // This voice-stealing algorithm applies the following heuristics: | |||
| @@ -205,17 +197,17 @@ MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceF | |||
| Array<MPESynthesiserVoice*> usableVoices; | |||
| usableVoices.ensureStorageAllocated (voices.size()); | |||
| for (int i = 0; i < voices.size(); ++i) | |||
| for (auto* voice : voices) | |||
| { | |||
| MPESynthesiserVoice* const voice = voices.getUnchecked (i); | |||
| jassert (voice->isActive()); // We wouldn't be here otherwise | |||
| MPEVoiceAgeSorter sorter; | |||
| usableVoices.addSorted (sorter, voice); | |||
| usableVoices.add (voice); | |||
| std::sort (usableVoices.begin(), usableVoices.end(), | |||
| [] (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) { return a->wasStartedBefore (*b); }); | |||
| if (! voice->isPlayingButReleased()) // Don't protect released notes | |||
| { | |||
| const int noteNumber = voice->getCurrentlyPlayingNote().initialNote; | |||
| auto noteNumber = voice->getCurrentlyPlayingNote().initialNote; | |||
| if (low == nullptr || noteNumber < low->getCurrentlyPlayingNote().initialNote) | |||
| low = voice; | |||
| @@ -229,49 +221,29 @@ MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceF | |||
| if (top == low) | |||
| top = nullptr; | |||
| const int numUsableVoices = usableVoices.size(); | |||
| // If we want to re-use the voice to trigger a new note, | |||
| // then The oldest note that's playing the same note number is ideal. | |||
| if (noteToStealVoiceFor.isValid()) | |||
| { | |||
| for (int i = 0; i < numUsableVoices; ++i) | |||
| { | |||
| MPESynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| for (auto* voice : usableVoices) | |||
| if (voice->getCurrentlyPlayingNote().initialNote == noteToStealVoiceFor.initialNote) | |||
| return voice; | |||
| } | |||
| } | |||
| // Oldest voice that has been released (no finger on it and not held by sustain pedal) | |||
| for (int i = 0; i < numUsableVoices; ++i) | |||
| { | |||
| MPESynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| for (auto* voice : usableVoices) | |||
| if (voice != low && voice != top && voice->isPlayingButReleased()) | |||
| return voice; | |||
| } | |||
| // Oldest voice that doesn't have a finger on it: | |||
| for (int i = 0; i < numUsableVoices; ++i) | |||
| { | |||
| MPESynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| for (auto* voice : usableVoices) | |||
| if (voice != low && voice != top | |||
| && voice->getCurrentlyPlayingNote().keyState != MPENote::keyDown | |||
| && voice->getCurrentlyPlayingNote().keyState != MPENote::keyDownAndSustained) | |||
| return voice; | |||
| } | |||
| // Oldest voice that isn't protected | |||
| for (int i = 0; i < numUsableVoices; ++i) | |||
| { | |||
| MPESynthesiserVoice* const voice = usableVoices.getUnchecked (i); | |||
| for (auto* voice : usableVoices) | |||
| if (voice != low && voice != top) | |||
| return voice; | |||
| } | |||
| // We've only got "protected" voices now: lowest note takes priority | |||
| jassert (low != nullptr); | |||
| @@ -489,14 +489,6 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, | |||
| return nullptr; | |||
| } | |||
| struct VoiceAgeSorter | |||
| { | |||
| static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept | |||
| { | |||
| return v1->wasStartedBefore (*v2) ? -1 : (v2->wasStartedBefore (*v1) ? 1 : 0); | |||
| } | |||
| }; | |||
| SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| int /*midiChannel*/, int midiNoteNumber) const | |||
| { | |||
| @@ -521,8 +513,9 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
| { | |||
| jassert (voice->isVoiceActive()); // We wouldn't be here otherwise | |||
| VoiceAgeSorter sorter; | |||
| usableVoices.addSorted (sorter, voice); | |||
| usableVoices.add (voice); | |||
| std::sort (usableVoices.begin(), usableVoices.end(), | |||
| [] (const SynthesiserVoice* a, const SynthesiserVoice* b) { return a->wasStartedBefore (*b); }); | |||
| if (! voice->isPlayingButReleased()) // Don't protect released notes | |||
| { | |||
| @@ -266,8 +266,7 @@ struct PluginSorter | |||
| PluginSorter (KnownPluginList::SortMethod sortMethod, bool forwards) noexcept | |||
| : method (sortMethod), direction (forwards ? 1 : -1) {} | |||
| int compareElements (const PluginDescription* const first, | |||
| const PluginDescription* const second) const | |||
| bool operator() (const PluginDescription* first, const PluginDescription* second) const | |||
| { | |||
| int diff = 0; | |||
| @@ -284,7 +283,7 @@ struct PluginSorter | |||
| if (diff == 0) | |||
| diff = first->name.compareNatural (second->name, true); | |||
| return diff * direction; | |||
| return diff * direction < 0; | |||
| } | |||
| private: | |||
| @@ -301,10 +300,8 @@ private: | |||
| return 0; | |||
| } | |||
| const KnownPluginList::SortMethod method; | |||
| const int direction; | |||
| JUCE_DECLARE_NON_COPYABLE (PluginSorter) | |||
| KnownPluginList::SortMethod method; | |||
| int direction; | |||
| }; | |||
| void KnownPluginList::sort (const SortMethod method, bool forwards) | |||
| @@ -317,10 +314,7 @@ void KnownPluginList::sort (const SortMethod method, bool forwards) | |||
| ScopedLock lock (typesArrayLock); | |||
| oldOrder.addArray (types); | |||
| PluginSorter sorter (method, forwards); | |||
| types.sort (sorter, true); | |||
| std::stable_sort (types.begin(), types.end(), PluginSorter (method, forwards)); | |||
| newOrder.addArray (types); | |||
| } | |||
| @@ -531,12 +525,11 @@ KnownPluginList::PluginTree* KnownPluginList::createTree (const SortMethod sortM | |||
| { | |||
| ScopedLock lock (typesArrayLock); | |||
| PluginSorter sorter (sortMethod, true); | |||
| for (auto* t : types) | |||
| sorted.addSorted (sorter, t); | |||
| sorted.addArray (types); | |||
| } | |||
| std::stable_sort (sorted.begin(), sorted.end(), PluginSorter (sortMethod, true)); | |||
| auto* tree = new PluginTree(); | |||
| if (sortMethod == sortByCategory || sortMethod == sortByManufacturer || sortMethod == sortByFormat) | |||
| @@ -115,7 +115,7 @@ void StringArray::clearQuick() | |||
| strings.clearQuick(); | |||
| } | |||
| const String& StringArray::operator[] (const int index) const noexcept | |||
| const String& StringArray::operator[] (int index) const noexcept | |||
| { | |||
| if (isPositiveAndBelow (index, strings.size())) | |||
| return strings.getReference (index); | |||
| @@ -128,7 +128,7 @@ const String& StringArray::operator[] (const int index) const noexcept | |||
| #endif | |||
| } | |||
| String& StringArray::getReference (const int index) noexcept | |||
| String& StringArray::getReference (int index) noexcept | |||
| { | |||
| return strings.getReference (index); | |||
| } | |||
| @@ -143,12 +143,12 @@ void StringArray::add (String&& stringToAdd) | |||
| strings.add (static_cast<String&&> (stringToAdd)); | |||
| } | |||
| void StringArray::insert (const int index, const String& newString) | |||
| void StringArray::insert (int index, const String& newString) | |||
| { | |||
| strings.insert (index, newString); | |||
| } | |||
| bool StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase) | |||
| bool StringArray::addIfNotAlreadyThere (const String& newString, bool ignoreCase) | |||
| { | |||
| if (contains (newString, ignoreCase)) | |||
| return false; | |||
| @@ -172,23 +172,23 @@ void StringArray::addArray (const StringArray& otherArray, int startIndex, int n | |||
| strings.add (otherArray.strings.getReference (startIndex++)); | |||
| } | |||
| void StringArray::mergeArray (const StringArray& otherArray, const bool ignoreCase) | |||
| void StringArray::mergeArray (const StringArray& otherArray, bool ignoreCase) | |||
| { | |||
| for (auto& s : otherArray) | |||
| addIfNotAlreadyThere (s, ignoreCase); | |||
| } | |||
| void StringArray::set (const int index, const String& newString) | |||
| void StringArray::set (int index, const String& newString) | |||
| { | |||
| strings.set (index, newString); | |||
| } | |||
| bool StringArray::contains (StringRef stringToLookFor, const bool ignoreCase) const | |||
| bool StringArray::contains (StringRef stringToLookFor, bool ignoreCase) const | |||
| { | |||
| return indexOf (stringToLookFor, ignoreCase) >= 0; | |||
| } | |||
| int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int i) const | |||
| int StringArray::indexOf (StringRef stringToLookFor, bool ignoreCase, int i) const | |||
| { | |||
| if (i < 0) | |||
| i = 0; | |||
| @@ -211,7 +211,7 @@ int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int | |||
| return -1; | |||
| } | |||
| void StringArray::move (const int currentIndex, const int newIndex) noexcept | |||
| void StringArray::move (int currentIndex, int newIndex) noexcept | |||
| { | |||
| strings.move (currentIndex, newIndex); | |||
| } | |||
| @@ -222,7 +222,7 @@ void StringArray::remove (int index) | |||
| strings.remove (index); | |||
| } | |||
| void StringArray::removeString (StringRef stringToRemove, const bool ignoreCase) | |||
| void StringArray::removeString (StringRef stringToRemove, bool ignoreCase) | |||
| { | |||
| if (ignoreCase) | |||
| { | |||
| @@ -244,7 +244,7 @@ void StringArray::removeRange (int startIndex, int numberToRemove) | |||
| } | |||
| //============================================================================== | |||
| void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) | |||
| void StringArray::removeEmptyStrings (bool removeWhitespaceStrings) | |||
| { | |||
| if (removeWhitespaceStrings) | |||
| { | |||
| @@ -267,39 +267,19 @@ void StringArray::trim() | |||
| } | |||
| //============================================================================== | |||
| struct InternalStringArrayComparator_CaseSensitive | |||
| { | |||
| static int compareElements (String& s1, String& s2) noexcept { return s1.compare (s2); } | |||
| }; | |||
| struct InternalStringArrayComparator_CaseInsensitive | |||
| { | |||
| static int compareElements (String& s1, String& s2) noexcept { return s1.compareIgnoreCase (s2); } | |||
| }; | |||
| struct InternalStringArrayComparator_Natural | |||
| { | |||
| static int compareElements (String& s1, String& s2) noexcept { return s1.compareNatural (s2); } | |||
| }; | |||
| void StringArray::sort (const bool ignoreCase) | |||
| void StringArray::sort (bool ignoreCase) | |||
| { | |||
| if (ignoreCase) | |||
| { | |||
| InternalStringArrayComparator_CaseInsensitive comp; | |||
| strings.sort (comp); | |||
| } | |||
| std::sort (strings.begin(), strings.end(), | |||
| [] (const String& a, const String& b) { return a.compareIgnoreCase (b) < 0; }); | |||
| else | |||
| { | |||
| InternalStringArrayComparator_CaseSensitive comp; | |||
| strings.sort (comp); | |||
| } | |||
| std::sort (strings.begin(), strings.end()); | |||
| } | |||
| void StringArray::sortNatural() | |||
| { | |||
| InternalStringArrayComparator_Natural comp; | |||
| strings.sort (comp); | |||
| std::sort (strings.begin(), strings.end(), | |||
| [] (const String& a, const String& b) { return a.compareNatural (b) < 0; }); | |||
| } | |||
| //============================================================================== | |||
| @@ -340,7 +320,6 @@ String StringArray::joinIntoString (StringRef separator, int start, int numberTo | |||
| } | |||
| dest.writeNull(); | |||
| return result; | |||
| } | |||
| @@ -426,7 +405,7 @@ StringArray StringArray::fromLines (StringRef stringToBreakUp) | |||
| } | |||
| //============================================================================== | |||
| void StringArray::removeDuplicates (const bool ignoreCase) | |||
| void StringArray::removeDuplicates (bool ignoreCase) | |||
| { | |||
| for (int i = 0; i < size() - 1; ++i) | |||
| { | |||
| @@ -444,8 +423,8 @@ void StringArray::removeDuplicates (const bool ignoreCase) | |||
| } | |||
| } | |||
| void StringArray::appendNumbersToDuplicates (const bool ignoreCase, | |||
| const bool appendNumberToFirstInstance, | |||
| void StringArray::appendNumbersToDuplicates (bool ignoreCase, | |||
| bool appendNumberToFirstInstance, | |||
| CharPointer_UTF8 preNumberString, | |||
| CharPointer_UTF8 postNumberString) | |||
| { | |||
| @@ -36,14 +36,6 @@ struct ZipFile::ZipEntryHolder | |||
| entry.filename = String::fromUTF8 (buffer + 46, fileNameLen); | |||
| } | |||
| struct FileNameComparator | |||
| { | |||
| static int compareElements (const ZipEntryHolder* e1, const ZipEntryHolder* e2) noexcept | |||
| { | |||
| return e1->entry.filename.compare (e2->entry.filename); | |||
| } | |||
| }; | |||
| static Time parseFileTime (uint32 time, uint32 date) noexcept | |||
| { | |||
| int year = 1980 + (date >> 9); | |||
| @@ -321,8 +313,8 @@ InputStream* ZipFile::createStreamForEntry (const ZipEntry& entry) | |||
| void ZipFile::sortEntriesByFilename() | |||
| { | |||
| ZipEntryHolder::FileNameComparator sorter; | |||
| entries.sort (sorter); | |||
| std::sort (entries.begin(), entries.end(), | |||
| [] (const ZipEntryHolder* e1, const ZipEntryHolder* e2) { return e1->entry.filename < e2->entry.filename; }); | |||
| } | |||
| //============================================================================== | |||
| @@ -41,8 +41,9 @@ struct FFT::Engine | |||
| { | |||
| Engine (int priorityToUse) : enginePriority (priorityToUse) | |||
| { | |||
| EnginePriorityComparator comparator; | |||
| getEngines().addSorted (comparator, this); | |||
| auto& list = getEngines(); | |||
| list.add (this); | |||
| std::sort (list.begin(), list.end(), [] (Engine* a, Engine* b) { return b->enginePriority < a->enginePriority; }); | |||
| } | |||
| virtual ~Engine() {} | |||
| @@ -61,15 +62,6 @@ struct FFT::Engine | |||
| } | |||
| private: | |||
| struct EnginePriorityComparator | |||
| { | |||
| static int compareElements (Engine* first, Engine* second) noexcept | |||
| { | |||
| // sort in reverse order | |||
| return DefaultElementComparator<int>::compareElements (second->enginePriority, first->enginePriority); | |||
| } | |||
| }; | |||
| static Array<Engine*>& getEngines() | |||
| { | |||
| static Array<Engine*> engines; | |||
| @@ -148,6 +148,9 @@ public: | |||
| */ | |||
| PositionedGlyph& getGlyph (int index) const noexcept; | |||
| const PositionedGlyph* begin() const { return glyphs.begin(); } | |||
| const PositionedGlyph* end() const { return glyphs.end(); } | |||
| //============================================================================== | |||
| /** Clears all text from the arrangement and resets it. */ | |||
| void clear(); | |||
| @@ -217,29 +217,29 @@ private: | |||
| GlyphArrangement ga; | |||
| ga.addLineOfText (font, chars, 0, 0); | |||
| Array<float> y; | |||
| DefaultElementComparator<float> sorter; | |||
| Array<float> yValues; | |||
| for (int i = 0; i < ga.getNumGlyphs(); ++i) | |||
| for (auto& glyph : ga) | |||
| { | |||
| Path p; | |||
| ga.getGlyph (i).createPath (p); | |||
| Rectangle<float> bounds (p.getBounds()); | |||
| glyph.createPath (p); | |||
| auto bounds = p.getBounds(); | |||
| if (! p.isEmpty()) | |||
| y.addSorted (sorter, getTop ? bounds.getY() : bounds.getBottom()); | |||
| yValues.add (getTop ? bounds.getY() : bounds.getBottom()); | |||
| } | |||
| float median = y[y.size() / 2]; | |||
| std::sort (yValues.begin(), yValues.end()); | |||
| auto median = yValues[yValues.size() / 2]; | |||
| float total = 0; | |||
| int num = 0; | |||
| for (int i = 0; i < y.size(); ++i) | |||
| for (auto y : yValues) | |||
| { | |||
| if (std::abs (median - y.getUnchecked(i)) < 0.05f * (float) standardHeight) | |||
| if (std::abs (median - y) < 0.05f * (float) standardHeight) | |||
| { | |||
| total += y.getUnchecked(i); | |||
| total += y; | |||
| ++num; | |||
| } | |||
| } | |||
| @@ -363,15 +363,14 @@ Path DrawableText::getOutlineAsPath() const | |||
| Path pathOfAllGlyphs; | |||
| for (int i = 0; i < arr.getNumGlyphs(); ++i) | |||
| for (auto& glyph : arr) | |||
| { | |||
| Path gylphPath; | |||
| arr.getGlyph (i).createPath (gylphPath); | |||
| glyph.createPath (gylphPath); | |||
| pathOfAllGlyphs.addPath (gylphPath); | |||
| } | |||
| pathOfAllGlyphs.applyTransform (getTextTransform (w, h) | |||
| .followedBy (getTransform())); | |||
| pathOfAllGlyphs.applyTransform (getTextTransform (w, h).followedBy (getTransform())); | |||
| return pathOfAllGlyphs; | |||
| } | |||
| @@ -216,20 +216,6 @@ bool DirectoryContentsList::checkNextFile (bool& hasChanged) | |||
| return false; | |||
| } | |||
| struct FileInfoComparator | |||
| { | |||
| static int compareElements (const DirectoryContentsList::FileInfo* const first, | |||
| const DirectoryContentsList::FileInfo* const second) | |||
| { | |||
| #if JUCE_WINDOWS | |||
| if (first->isDirectory != second->isDirectory) | |||
| return first->isDirectory ? -1 : 1; | |||
| #endif | |||
| return first->filename.compareNatural (second->filename); | |||
| } | |||
| }; | |||
| bool DirectoryContentsList::addFile (const File& file, const bool isDir, | |||
| const int64 fileSize, | |||
| Time modTime, Time creationTime, | |||
| @@ -254,8 +240,18 @@ bool DirectoryContentsList::addFile (const File& file, const bool isDir, | |||
| if (files.getUnchecked(i)->filename == info->filename) | |||
| return false; | |||
| FileInfoComparator comp; | |||
| files.addSorted (comp, info.release()); | |||
| files.add (info.release()); | |||
| std::sort (files.begin(), files.end(), [] (const FileInfo* a, const FileInfo* b) | |||
| { | |||
| #if JUCE_WINDOWS | |||
| if (a->isDirectory != b->isDirectory) | |||
| return a->isDirectory; | |||
| #endif | |||
| return a->filename.compareNatural (b->filename) < 0; | |||
| }); | |||
| return true; | |||
| } | |||
| @@ -29,41 +29,38 @@ namespace juce | |||
| namespace KeyboardFocusHelpers | |||
| { | |||
| // This will sort a set of components, so that they are ordered in terms of | |||
| // left-to-right and then top-to-bottom. | |||
| struct ScreenPositionComparator | |||
| static int getOrder (const Component* c) | |||
| { | |||
| static int compareElements (const Component* first, const Component* second) | |||
| { | |||
| auto explicitOrder1 = getOrder (first); | |||
| auto explicitOrder2 = getOrder (second); | |||
| if (explicitOrder1 != explicitOrder2) | |||
| return explicitOrder1 - explicitOrder2; | |||
| auto yDiff = first->getY() - second->getY(); | |||
| return yDiff == 0 ? first->getX() - second->getX() | |||
| : yDiff; | |||
| } | |||
| static int getOrder (const Component* c) | |||
| { | |||
| auto order = c->getExplicitFocusOrder(); | |||
| return order > 0 ? order : (std::numeric_limits<int>::max() / 2); | |||
| } | |||
| }; | |||
| auto order = c->getExplicitFocusOrder(); | |||
| return order > 0 ? order : (std::numeric_limits<int>::max() / 2); | |||
| } | |||
| static void findAllFocusableComponents (Component* parent, Array<Component*>& comps) | |||
| { | |||
| if (parent->getNumChildComponents() != 0) | |||
| { | |||
| Array<Component*> localComps; | |||
| ScreenPositionComparator comparator; | |||
| for (auto* c : parent->getChildren()) | |||
| if (c->isVisible() && c->isEnabled()) | |||
| localComps.addSorted (comparator, c); | |||
| localComps.add (c); | |||
| // This will sort so that they are ordered in terms of left-to-right | |||
| // and then top-to-bottom. | |||
| std::stable_sort (localComps.begin(), localComps.end(), | |||
| [] (const Component* a, const Component* b) | |||
| { | |||
| auto explicitOrder1 = getOrder (a); | |||
| auto explicitOrder2 = getOrder (b); | |||
| if (explicitOrder1 != explicitOrder2) | |||
| return explicitOrder1 < explicitOrder2; | |||
| if (a->getY() != b->getY()) | |||
| return a->getY() < b->getY(); | |||
| return a->getX() < b->getX(); | |||
| }); | |||
| for (auto* c : localComps) | |||
| { | |||
| @@ -111,7 +111,8 @@ struct FlexBoxLayoutCalculation | |||
| for (auto& item : owner.items) | |||
| itemStates.add (item); | |||
| itemStates.sort (*this, true); | |||
| std::stable_sort (itemStates.begin(), itemStates.end(), | |||
| [] (const ItemWithState& i1, const ItemWithState& i2) { return i1.item->order < i2.item->order; }); | |||
| for (auto& item : itemStates) | |||
| { | |||
| @@ -531,11 +532,6 @@ struct FlexBoxLayoutCalculation | |||
| reverseWrap(); | |||
| } | |||
| static int compareElements (const ItemWithState& i1, const ItemWithState& i2) noexcept | |||
| { | |||
| return i1.item->order < i2.item->order ? -1 : (i2.item->order < i1.item->order ? 1 : 0); | |||
| } | |||
| private: | |||
| void resetRowItems (const int row) noexcept | |||
| { | |||
| @@ -737,7 +737,8 @@ struct Grid::AutoPlacement | |||
| for (auto& item : grid.items) | |||
| sortedItems.add (&item); | |||
| sortedItems.sort (*this, true); | |||
| std::stable_sort (sortedItems.begin(), sortedItems.end(), | |||
| [] (const GridItem* i1, const GridItem* i2) { return i1->order < i2->order; }); | |||
| // place fixed items first | |||
| for (auto* item : sortedItems) | |||
| @@ -843,12 +844,6 @@ struct Grid::AutoPlacement | |||
| return { implicitColumnTracks, implicitRowTracks }; | |||
| } | |||
| //============================================================================== | |||
| static int compareElements (const GridItem* i1, const GridItem* i2) noexcept | |||
| { | |||
| return i1->order < i2->order ? -1 : (i2->order < i1->order ? 1 : 0); | |||
| } | |||
| //============================================================================== | |||
| static void applySizeForAutoTracks (juce::Array<Grid::TrackInfo>& columns, | |||
| juce::Array<Grid::TrackInfo>& rows, | |||
| @@ -1302,34 +1302,6 @@ private: | |||
| } | |||
| } | |||
| //============================================================================== | |||
| struct SortByCoordinate | |||
| { | |||
| bool sortByYCoordinate; | |||
| SortByCoordinate (bool byYCoordinate) : sortByYCoordinate (byYCoordinate) | |||
| { | |||
| } | |||
| int compareElements (const ExtendedInfo* a, const ExtendedInfo* b) | |||
| { | |||
| int coordinateA, coordinateB; | |||
| if (sortByYCoordinate) | |||
| { | |||
| coordinateA = a->totalBounds.getY(); | |||
| coordinateB = b->totalBounds.getY(); | |||
| } | |||
| else | |||
| { | |||
| coordinateA = a->totalBounds.getX(); | |||
| coordinateB = b->totalBounds.getX(); | |||
| } | |||
| return coordinateA - coordinateB; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| void updateScaledDisplayCoordinate (bool updateYCoordinates) | |||
| { | |||
| @@ -1337,11 +1309,17 @@ private: | |||
| return; | |||
| Array<ExtendedInfo*> copy; | |||
| for (auto& i : infos) | |||
| copy.add (&i); | |||
| std::sort (copy.begin(), copy.end(), [updateYCoordinates] (const ExtendedInfo* a, const ExtendedInfo* b) | |||
| { | |||
| SortByCoordinate sorter (updateYCoordinates); | |||
| for (int i = 0; i < infos.size(); ++i) | |||
| copy.addSorted (sorter, &infos.getReference (i)); | |||
| } | |||
| if (updateYCoordinates) | |||
| return a->totalBounds.getY() < b->totalBounds.getY(); | |||
| return a->totalBounds.getX() < b->totalBounds.getX(); | |||
| }); | |||
| for (int i = 1; i < copy.size(); ++i) | |||
| { | |||
| @@ -1351,13 +1329,14 @@ private: | |||
| for (int j = i - 1; j >= 0; --j) | |||
| { | |||
| auto& other = *copy[j]; | |||
| int prevCoordinate = updateYCoordinates ? other.totalBounds.getBottom() : other.totalBounds.getRight(); | |||
| int curCoordinate = updateYCoordinates ? current.totalBounds.getY() : current.totalBounds.getX(); | |||
| auto prevCoordinate = updateYCoordinates ? other.totalBounds.getBottom() : other.totalBounds.getRight(); | |||
| auto curCoordinate = updateYCoordinates ? current.totalBounds.getY() : current.totalBounds.getX(); | |||
| if (prevCoordinate == curCoordinate) | |||
| { | |||
| // both displays are aligned! As "other" comes before "current" in the array, it must already | |||
| // have a valid topLeftScaled which we can use | |||
| Point<int> topLeftScaled = other.topLeftScaled; | |||
| auto topLeftScaled = other.topLeftScaled; | |||
| topLeftScaled += Point<int> (other.totalBounds.getWidth(), other.totalBounds.getHeight()) / other.scale; | |||
| if (updateYCoordinates) | |||