1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-21 06:40:08 +02:00

Update to Clip Boundary commands

This update affects the four commands:
Cursor to Previous clip boundary
Cursor to Next clip boundary
Select previous clip boundary to cursor
Select cursor to next clip boundary

Previously these commands all used the clips in the focused track. This update changes this so that their behaviour is the same as the Tracks->Pan->Left/Right/Center commands. That is, if any audio tracks are selected, all the clips in these tracks are used, else the clips in all audio tracks are used.
This commit is contained in:
David Bailes 2017-04-13 13:36:19 +01:00
parent 0b942d04b7
commit ce1d067f84
2 changed files with 131 additions and 81 deletions

View File

@ -5490,37 +5490,23 @@ void AudacityProject::OnSelectCursorToNextClipBoundary()
void AudacityProject::OnSelectClipBoundary(bool next)
{
const auto track = mTrackPanel->GetFocusedTrack();
std::vector<FoundClipBoundary> results;
int nTracksSearched = FindClipBoundaries(next ? mViewInfo.selectedRegion.t1() :
mViewInfo.selectedRegion.t0(), next, results);
if (track && track->GetKind() == Track::Wave) {
const auto wt = static_cast<WaveTrack*>(track);
if (wt->GetNumClips()) {
auto result = next ? FindNextClipBoundary(wt, mViewInfo.selectedRegion.t1()) :
FindPrevClipBoundary(wt, mViewInfo.selectedRegion.t0());
if (results.size() > 0) {
// note that if there is more than one result, each has the same time value.
if (next)
mViewInfo.selectedRegion.setT1(results[0].time);
else
mViewInfo.selectedRegion.setT0(results[0].time);
if (result.nFound > 0) {
if (next)
mViewInfo.selectedRegion.setT1(result.time);
else
mViewInfo.selectedRegion.setT0(result.time);
ModifyState(false);
mTrackPanel->Refresh(false);
ModifyState(false);
mTrackPanel->Refresh(false);
wxString message;
message.Printf(wxT("%d %s %d %s"), result.index1 + 1, _("of"), wt->GetNumClips(),
result.clipStart1 ? _("start") : _("end"));
if (result.nFound == 2) {
wxString messageAdd;
messageAdd.Printf(wxT(" %s %d %s"), _("and"), result.index2 + 1,
result.clipStart2 ? _("start") : _("end"));
message += messageAdd;
}
mTrackPanel->MessageForScreenReader(message);
}
}
wxString message = ClipBoundaryMessage(nTracksSearched, results);
mTrackPanel->MessageForScreenReader(message);
}
}
void AudacityProject::OnSelectPrevClip()
@ -6421,39 +6407,40 @@ void AudacityProject::OnCursorSelEnd()
AudacityProject::FoundClipBoundary AudacityProject::FindNextClipBoundary(const WaveTrack* wt, double time)
{
AudacityProject::FoundClipBoundary result{};
result.waveTrack = wt;
const auto clips = wt->SortedClipArray();
auto resultStart = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
auto pStart = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
return clip->GetStartTime() > time; });
auto resultEnd = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
auto pEnd = std::find_if(clips.begin(), clips.end(), [&] (const WaveClip* const& clip) {
return clip->GetEndTime() > time; });
if (resultStart != clips.end() && resultEnd != clips.end()) {
if ((*resultStart)->GetStartTime() < (*resultEnd)->GetEndTime()) {
if (pStart != clips.end() && pEnd != clips.end()) {
if ((*pStart)->GetStartTime() < (*pEnd)->GetEndTime()) {
result.nFound = 1;
result.time = (*resultStart)->GetStartTime();
result.index1 = resultStart - clips.begin();
result.time = (*pStart)->GetStartTime();
result.index1 = std::distance(clips.begin(), pStart);
result.clipStart1 = true;
}
else if ((*resultStart)->GetStartTime() > (*resultEnd)->GetEndTime()) {
else if ((*pStart)->GetStartTime() > (*pEnd)->GetEndTime()) {
result.nFound = 1;
result.time = (*resultEnd)->GetEndTime();
result.index1 = resultEnd - clips.begin();
result.time = (*pEnd)->GetEndTime();
result.index1 = std::distance(clips.begin(), pEnd);
result.clipStart1 = false;
}
else { // both the end of one clip and the start of the next clip
result.nFound = 2;
result.time = (*resultEnd)->GetEndTime();
result.index1 = resultEnd - clips.begin();
result.time = (*pEnd)->GetEndTime();
result.index1 = std::distance(clips.begin(), pEnd);
result.clipStart1 = false;
result.index2 = resultStart - clips.begin();
result.index2 = std::distance(clips.begin(), pStart);
result.clipStart2 = true;
}
}
else if (resultEnd != clips.end()) {
else if (pEnd != clips.end()) {
result.nFound = 1;
result.time = (*resultEnd)->GetEndTime();
result.index1 = resultEnd - clips.begin();
result.time = (*pEnd)->GetEndTime();
result.index1 = std::distance(clips.begin(), pEnd);
result.clipStart1 = false;
}
@ -6463,45 +6450,85 @@ AudacityProject::FoundClipBoundary AudacityProject::FindNextClipBoundary(const W
AudacityProject::FoundClipBoundary AudacityProject::FindPrevClipBoundary(const WaveTrack* wt, double time)
{
AudacityProject::FoundClipBoundary result{};
result.waveTrack = wt;
const auto clips = wt->SortedClipArray();
auto resultStart = std::find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
auto pStart = std::find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
return clip->GetStartTime() < time; });
auto resultEnd = std::find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
auto pEnd = std::find_if(clips.rbegin(), clips.rend(), [&] (const WaveClip* const& clip) {
return clip->GetEndTime() < time; });
if (resultStart != clips.rend() && resultEnd != clips.rend()) {
if ((*resultStart)->GetStartTime() > (*resultEnd)->GetEndTime()) {
if (pStart != clips.rend() && pEnd != clips.rend()) {
if ((*pStart)->GetStartTime() > (*pEnd)->GetEndTime()) {
result.nFound = 1;
result.time = (*resultStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
result.time = (*pStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - std::distance(clips.rbegin(), pStart);
result.clipStart1 = true;
}
else if ((*resultStart)->GetStartTime() < (*resultEnd)->GetEndTime()) {
else if ((*pStart)->GetStartTime() < (*pEnd)->GetEndTime()) {
result.nFound = 1;
result.time = (*resultEnd)->GetEndTime();
result.index1 = static_cast<int>(clips.size()) - 1 - (resultEnd - clips.rbegin());
result.time = (*pEnd)->GetEndTime();
result.index1 = static_cast<int>(clips.size()) - 1 - std::distance(clips.rbegin(), pEnd);
result.clipStart1 = false;
}
else {
result.nFound = 2; // both the start of one clip and the end of the previous clip
result.time = (*resultStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
result.time = (*pStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - std::distance(clips.rbegin(), pStart);
result.clipStart1 = true;
result.index2 = static_cast<int>(clips.size()) - 1 - (resultEnd - clips.rbegin());
result.index2 = static_cast<int>(clips.size()) - 1 - std::distance(clips.rbegin(), pEnd);
result.clipStart2 = false;
}
}
else if (resultStart != clips.rend()) {
else if (pStart != clips.rend()) {
result.nFound = 1;
result.time = (*resultStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - (resultStart - clips.rbegin());
result.time = (*pStart)->GetStartTime();
result.index1 = static_cast<int>(clips.size()) - 1 - std::distance(clips.rbegin(), pStart);
result.clipStart1 = true;
}
return result;
}
int AudacityProject::FindClipBoundaries(double time, bool next, std::vector<FoundClipBoundary>& finalResults)
{
const TrackList* tracks = GetTracks();
finalResults.clear();
bool anyWaveTracksSelected = std::any_of(tracks->begin(), tracks->end(), [] (const movable_ptr<Track>& t) {
return t->GetSelected() && t->GetKind() == Track::Wave; });
// first search the tracks individually
std::vector<FoundClipBoundary> results;
int nTracksSearched = 0;
for (auto& track : *tracks) {
if ( track->GetKind() == Track::Wave && (!anyWaveTracksSelected || track->GetSelected())) {
auto waveTrack = static_cast<const WaveTrack*>(track.get());
auto result = next ? FindNextClipBoundary(waveTrack, time) :
FindPrevClipBoundary(waveTrack, time);
nTracksSearched++;
if (result.nFound > 0)
results.push_back(result);
}
}
if (results.size() > 0) {
// If any clip boundaries were found
// find the clip boundary or boundaries with the min/max time
auto compare = [] (const FoundClipBoundary& a, const FoundClipBoundary&b)
{ return a.time < b.time; };
auto p = next ? min_element(results.begin(), results.end(), compare ) :
max_element(results.begin(), results.end(), compare);
std::copy_if(results.begin(), results.end(), std::back_inserter(finalResults),
[&] (const FoundClipBoundary& r) { return r.time == (*p).time; });
}
return nTracksSearched;
}
void AudacityProject::OnCursorNextClipBoundary()
{
OnCursorClipBoundary(true);
@ -6514,35 +6541,55 @@ void AudacityProject::OnCursorPrevClipBoundary()
void AudacityProject::OnCursorClipBoundary(bool next)
{
const auto track = mTrackPanel->GetFocusedTrack();
std::vector<FoundClipBoundary> results;
int nTracksSearched = FindClipBoundaries(mViewInfo.selectedRegion.t0(), next, results);
if (track && track->GetKind() == Track::Wave) {
const auto wt = static_cast<WaveTrack*>(track);
if (wt->GetNumClips()) {
auto result = next ? FindNextClipBoundary(wt, mViewInfo.selectedRegion.t0()) :
FindPrevClipBoundary(wt, mViewInfo.selectedRegion.t0());
if (results.size() > 0) {
// note that if there is more than one result, each has the same time value.
double time = results[0].time;
mViewInfo.selectedRegion.setTimes(time, time);
ModifyState(false);
mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0());
mTrackPanel->Refresh(false);
if (result.nFound > 0) {
mViewInfo.selectedRegion.setTimes(result.time, result.time);
ModifyState(false);
mTrackPanel->ScrollIntoView(mViewInfo.selectedRegion.t0());
mTrackPanel->Refresh(false);
wxString message;
message.Printf(wxT("%d %s %d %s"), result.index1 + 1, _("of"), wt->GetNumClips(),
result.clipStart1 ? _("start") : _("end"));
if (result.nFound == 2) {
wxString messageAdd;
messageAdd.Printf(wxT(" %s %d %s"), _("and"), result.index2 + 1,
result.clipStart2 ? _("start") : _("end"));
message += messageAdd;
}
mTrackPanel->MessageForScreenReader(message);
}
}
wxString message = ClipBoundaryMessage(nTracksSearched, results);
mTrackPanel->MessageForScreenReader(message);
}
}
// for clip boundary commands, create a message for screen readers
wxString AudacityProject::ClipBoundaryMessage(int nTracksSearched, const std::vector<FoundClipBoundary>& results)
{
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<Track>& t) { return t.get() == result.waveTrack; });
temp.Printf(wxT("%s %d "), _("Track"), std::distance(GetTracks()->begin(), track) + 1);
}
else
temp.Printf( wxT("%s "), result.waveTrack->GetName());
message += temp;
}
message += (result.clipStart1 ? _("start") : _("end")) + wxT(" ");
if (result.waveTrack->GetNumClips() > 1 ) {
temp.Printf(wxT("%d %s %d "), result.index1 + 1, _("of"), result.waveTrack->GetNumClips());
message += temp;
}
if (result.nFound == 2) {
temp.Printf(wxT("%s %s %d "), _("and"), result.clipStart2 ? _("start") : _("end"),
result.index2 + 1);
message += temp;
}
message += wxT(", ");
}
return message;
}
void AudacityProject::HandleAlign(int index, bool moveSel)
{
TrackListIterator iter(GetTracks());

View File

@ -391,6 +391,7 @@ void OnCursorTrackEnd();
void OnCursorSelStart();
void OnCursorSelEnd();
typedef struct FoundClipBoundary {
const WaveTrack* waveTrack;
int nFound; // 0, 1, or 2
double time;
int index1;
@ -400,9 +401,11 @@ typedef struct FoundClipBoundary {
} FoundClipBoundary;
FoundClipBoundary FindNextClipBoundary(const WaveTrack* wt, double time);
FoundClipBoundary FindPrevClipBoundary(const WaveTrack* wt, double time);
int FindClipBoundaries(double time, bool next, std::vector<FoundClipBoundary>& results);
void OnCursorNextClipBoundary();
void OnCursorPrevClipBoundary();
void OnCursorClipBoundary(bool next);
wxString ClipBoundaryMessage(int nTracksSearched, const std::vector<FoundClipBoundary>& results);
void OnAlignNoSync(int index);
void OnAlign(int index);