From baf46c1f855501fce572a20fb3676d9d2dd41bf0 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Thu, 27 Apr 2017 11:28:33 +0100 Subject: [PATCH] Update to Select Previous/Next clip commands Previously, these two commands used the clips in the focused track. They now have similar to the Tracks->Pan->Left/Right/Center commands. That is if any audio tracks are selected, the clips in these tracks are used, otherwise the clips in all audio tracks are used. --- src/Menus.cpp | 185 +++++++++++++++++++++++++++++++++++++++----------- src/Menus.h | 10 +++ 2 files changed, 156 insertions(+), 39 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 82084ae3f..d26efead2 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -5509,6 +5509,120 @@ void AudacityProject::OnSelectClipBoundary(bool next) } } +AudacityProject::FoundClip AudacityProject::FindNextClip(const WaveTrack* wt, double t0, double t1) +{ + AudacityProject::FoundClip result{}; + result.waveTrack = wt; + const auto clips = wt->SortedClipArray(); + + auto p = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) { + return clip->GetStartTime() == t0; }); + if (p != clips.end() && (*p)->GetEndTime() > t1) { + result.found = true; + result.startTime = (*p)->GetStartTime(); + result.endTime = (*p)->GetEndTime(); + result.index = std::distance(clips.begin(), p); + } + else { + auto p = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) { + return clip->GetStartTime() > t0; }); + if (p != clips.end()) { + result.found = true; + result.startTime = (*p)->GetStartTime(); + result.endTime = (*p)->GetEndTime(); + result.index = std::distance(clips.begin(), p); + } + } + + return result; +} + +AudacityProject::FoundClip AudacityProject::FindPrevClip(const WaveTrack* wt, double t0, double t1) +{ + AudacityProject::FoundClip result{}; + result.waveTrack = wt; + const auto clips = wt->SortedClipArray(); + + auto p = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) { + return clip->GetStartTime() == t0; }); + if (p != clips.end() && (*p)->GetEndTime() < t1) { + result.found = true; + result.startTime = (*p)->GetStartTime(); + result.endTime = (*p)->GetEndTime(); + result.index = std::distance(clips.begin(), p); + } + else { + auto p = std::find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) { + return clip->GetStartTime() < t0; }); + if (p != clips.rend()) { + result.found = true; + result.startTime = (*p)->GetStartTime(); + result.endTime = (*p)->GetEndTime(); + result.index = static_cast(clips.size()) - 1 - std::distance(clips.rbegin(), p); + } + } + + return result; +} + +int AudacityProject::FindClips(double t0, double t1, bool next, std::vector& finalResults) +{ + const TrackList* tracks = GetTracks(); + finalResults.clear(); + + bool anyWaveTracksSelected = std::any_of(tracks->begin(), tracks->end(), [] (const movable_ptr& t) { + return t->GetSelected() && t->GetKind() == Track::Wave; }); + + // first search the tracks individually + std::vector results; + int nTracksSearched = 0; + for (auto& track : *tracks) { + if (track->GetKind() == Track::Wave && (!anyWaveTracksSelected || track->GetSelected())) { + auto waveTrack = static_cast(track.get()); + auto result = next ? FindNextClip(waveTrack, t0, t1) : + FindPrevClip(waveTrack, t0, t1); + nTracksSearched++; + if (result.found) + results.push_back(result); + } + } + + if (results.size() > 0) { + // if any clips were found, + // find the clip or clips with the min/max start time + auto compareStart = [] (const FoundClip& a, const FoundClip& b) + { return a.startTime < b.startTime; }; + + auto p = next ? std::min_element(results.begin(), results.end(), compareStart) : + std::max_element(results.begin(), results.end(), compareStart); + + std::vector resultsStartTime; + std::copy_if(results.begin(), results.end(), std::back_inserter(resultsStartTime), + [&] (const FoundClip& r) { return r.startTime == (*p).startTime; } ); + + if (resultsStartTime.size() > 1) { + // more than one clip with same start time so + // find the clip or clips with the min/max end time + auto compareEnd = [] (const FoundClip& a, const FoundClip& b) + { return a.endTime < b.endTime; }; + + auto p = next ? std::min_element(resultsStartTime.begin(), + resultsStartTime.end(), compareEnd) : + std::max_element(resultsStartTime.begin(), + resultsStartTime.end(), compareEnd); + + std::copy_if(resultsStartTime.begin(), resultsStartTime.end(), + std::back_inserter(finalResults), + [&] (const FoundClip& r) { return r.endTime == (*p).endTime; } ); + } + else { + finalResults = resultsStartTime; + } + } + + return nTracksSearched; +} + void AudacityProject::OnSelectPrevClip() { OnSelectClip(false); @@ -5521,50 +5635,43 @@ void AudacityProject::OnSelectNextClip() void AudacityProject::OnSelectClip(bool next) { - auto track = mTrackPanel->GetFocusedTrack(); + std::vector results; + int nTracksSearched = FindClips(mViewInfo.selectedRegion.t0(), + mViewInfo.selectedRegion.t1(), next, results); - if (track && track->GetKind() == Track::Wave) { - auto wt = static_cast(track); - const auto clips = wt->SortedClipArray(); - double t0 = mViewInfo.selectedRegion.t0(); - double t1 = mViewInfo.selectedRegion.t1(); - WaveClip* clip = nullptr; - int i = 0; + if (results.size() > 0) { + // note that if there is more than one result, each has the same start + // and end time + double t0 = results[0].startTime; + double t1 = results[0].endTime; + mViewInfo.selectedRegion.setTimes(t0, t1); + ModifyState(false); + mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0()); + mTrackPanel->Refresh(false); - if (next) { - auto result = std::find_if(clips.begin(), clips.end(), [&] (WaveClip* const& clip) { - return clip->GetStartTime() == t0; }); - if (result != clips.end() && (*result)->GetEndTime() != t1 ) { - clip = *result; - i = result - clips.begin(); - } - else { - auto result = std::find_if(clips.begin(), clips.end(), [&] (WaveClip* const& clip) { - return clip->GetStartTime() > t0; }); - if (result != clips.end()) { - clip = *result; - i = result - clips.begin(); + // create and send message to screen reader + wxString message; + for (auto& result : results) { + wxString temp; + + if (nTracksSearched > 1) { + if (result.waveTrack->GetName() == result.waveTrack->GetDefaultName()) { + auto track = std::find_if(GetTracks()->begin(), GetTracks()->end(), + [&] (const movable_ptr& t) { return t.get() == result.waveTrack; }); + temp.Printf(wxT("%s %d "), _("Track"), std::distance(GetTracks()->begin(), track) + 1); } - } - } - else { - auto result = std::find_if(clips.rbegin(), clips.rend(), [&] (WaveClip* const& clip) { - return clip->GetStartTime() < t0; }); - if (result != clips.rend()) { - clip = *result; - i = static_cast(clips.size()) - 1 - (result - clips.rbegin()); - } - } + else + temp.Printf(wxT("%s "), result.waveTrack->GetName()); - if (clip) { - mViewInfo.selectedRegion.setTimes(clip->GetStartTime(), clip->GetEndTime()); - mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0()); - ModifyState(false); - mTrackPanel->Refresh(false); - wxString message; - message.Printf(wxT("%d %s %d %s"), i + 1, _("of"), clips.size(), _("selected")); - mTrackPanel->MessageForScreenReader(message); + message += temp; + } + if (result.waveTrack->GetNumClips() > 1 || nTracksSearched == 1) { + temp.Printf(wxT("%d %s %d "), result.index + 1, _("of"), result.waveTrack->GetNumClips()); + message += temp; + } + message += wxT(", "); } + mTrackPanel->MessageForScreenReader(message); } } diff --git a/src/Menus.h b/src/Menus.h index 8ab4e147f..4fb2284c2 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -288,6 +288,16 @@ void OnSelectStartCursor(); void OnSelectPrevClipBoundaryToCursor(); void OnSelectCursorToNextClipBoundary(); void OnSelectClipBoundary(bool next); +typedef struct FoundClip { + const WaveTrack* waveTrack; + bool found; + double startTime; + double endTime; + int index; +} FoundClip; +FoundClip FindNextClip(const WaveTrack* wt, double t0, double t1); +FoundClip FindPrevClip(const WaveTrack* wt, double t0, double t1); +int FindClips(double t0, double t1, bool next, std::vector& results); void OnSelectPrevClip(); void OnSelectNextClip(); void OnSelectClip(bool next);