1#include "../CommonCommandFlags.h"
4#include "../TrackPanelAx.h"
5#include "../ProjectWindow.h"
10#include "../commands/CommandContext.h"
11#include "../commands/CommandManager.h"
12#include "../tracks/ui/TimeShiftHandle.h"
26 auto shortName = wxString::Format(
_(
"Track %d"), trackNum)
27 .Append(
" " + waveTrack->GetName());
60 const std::vector<const WaveClip*> & clips,
double time)
62 auto q = std::find_if(clips.begin(), clips.end(),
64 return clip->GetPlayEndTime() == time; });
65 if (q != clips.end() && q + 1 != clips.end() &&
66 (*q)->SharesBoundaryWithNextClip(*(q+1))) {
67 time = (*(q+1))->GetPlayStartTime();
82 const std::vector<const WaveClip*>& clips,
double time)
84 auto q = std::find_if(clips.begin(), clips.end(),
86 return clip->GetPlayStartTime() == time; });
87 if (q != clips.end() && q != clips.begin() &&
88 (*(q - 1))->SharesBoundaryWithNextClip(*q)) {
89 time = (*(q-1))->GetPlayEndTime();
104 auto pStart = std::find_if(clips.begin(), clips.end(),
106 return clip->GetPlayStartTime() > timeStart; });
107 auto pEnd = std::find_if(clips.begin(), clips.end(),
109 return clip->GetPlayEndTime() > timeEnd; });
111 if (pStart != clips.end() && pEnd != clips.end()) {
112 if ((*pEnd)->SharesBoundaryWithNextClip(*pStart)) {
115 result.time = (*pEnd)->GetPlayEndTime();
116 result.index1 = std::distance(clips.begin(), pEnd);
117 result.name1 = (*pEnd)->GetName();
118 result.clipStart1 =
false;
119 result.index2 = std::distance(clips.begin(), pStart);
120 result.name2 = (*pStart)->GetName();
121 result.clipStart2 =
true;
123 else if ((*pStart)->GetPlayStartTime() < (*pEnd)->GetPlayEndTime()) {
125 result.time = (*pStart)->GetPlayStartTime();
126 result.index1 = std::distance(clips.begin(), pStart);
127 result.name1 = (*pStart)->GetName();
128 result.clipStart1 =
true;
132 result.time = (*pEnd)->GetPlayEndTime();
133 result.index1 = std::distance(clips.begin(), pEnd);
134 result.name1 = (*pEnd)->GetName();
135 result.clipStart1 =
false;
138 else if (pEnd != clips.end()) {
140 result.time = (*pEnd)->GetPlayEndTime();
141 result.index1 = std::distance(clips.begin(), pEnd);
142 result.name1 = (*pEnd)->GetName();
143 result.clipStart1 =
false;
157 auto pStart = std::find_if(clips.rbegin(), clips.rend(),
159 return clip->GetPlayStartTime() < timeStart; });
160 auto pEnd = std::find_if(clips.rbegin(), clips.rend(),
162 return clip->GetPlayEndTime() < timeEnd; });
164 if (pStart != clips.rend() && pEnd != clips.rend()) {
165 if ((*pEnd)->SharesBoundaryWithNextClip(*pStart)) {
168 result.time = (*pStart)->GetPlayStartTime();
170 static_cast<int>(clips.size()) - 1 -
171 std::distance(clips.rbegin(), pStart);
172 result.name1 = (*pStart)->GetName();
173 result.clipStart1 =
true;
175 static_cast<int>(clips.size()) - 1 -
176 std::distance(clips.rbegin(), pEnd);
177 result.name2 = (*pEnd)->GetName();
178 result.clipStart2 =
false;
180 else if ((*pStart)->GetPlayStartTime() > (*pEnd)->GetPlayEndTime()) {
182 result.time = (*pStart)->GetPlayStartTime();
184 static_cast<int>(clips.size()) - 1 -
185 std::distance(clips.rbegin(), pStart);
186 result.name1 = (*pStart)->GetName();
187 result.clipStart1 =
true;
191 result.time = (*pEnd)->GetPlayEndTime();
193 static_cast<int>(clips.size()) - 1 -
194 std::distance(clips.rbegin(), pEnd);
195 result.name1 = (*pEnd)->GetName();
196 result.clipStart1 =
false;
199 else if (pStart != clips.rend()) {
201 result.time = (*pStart)->GetPlayStartTime();
203 static_cast<int>(clips.size()) - 1 -
204 std::distance(clips.rbegin(), pStart);
205 result.name1 = (*pStart)->GetName();
206 result.clipStart1 =
true;
214 double time,
bool next, std::vector<FoundClipBoundary>& finalResults)
217 finalResults.clear();
224 std::vector<FoundClipBoundary> results;
226 int nTracksSearched = 0;
227 auto leaders =
tracks.Any();
228 auto rangeLeaders = leaders.Filter<
const WaveTrack>();
229 if (anyWaveTracksSelected)
231 for (
auto waveTrack : rangeLeaders) {
234 if (result.nFound > 0) {
236 1 + std::distance(leaders.begin(), leaders.find(waveTrack));
237 results.push_back(result);
244 if (results.size() > 0) {
248 {
return a.
time < b.time; };
250 auto p = next ? min_element(results.begin(), results.end(), compare ) :
251 max_element(results.begin(), results.end(), compare);
253 for (
auto &r : results )
254 if ( r.time == (*p).time )
255 finalResults.push_back( r );
258 return nTracksSearched;
263 const std::vector<FoundClipBoundary>& results)
266 for (
auto& result : results) {
268 auto longName = result.ComposeTrackName();
271 auto nClips = result.waveTrack->GetNumClips();
272 if (result.nFound < 2) {
284 "%s %s, %d of %d clip %s",
285 "%s %s, %d of %d clips %s",
288 result.clipStart1 ?
XO(
"start") :
XO(
"end"),
307 "%s %s and %s %s, %d and %d of %d clip %s",
308 "%s %s and %s %s, %d and %d of %d clips %s",
311 result.clipStart1 ?
XO(
"start") :
XO(
"end"),
313 result.clipStart2 ?
XO(
"start") :
XO(
"end"),
325 message =
XO(
"%s, %s").Format( message,
str );
336 std::vector<FoundClipBoundary> results;
338 selectedRegion.t0(), next, results);
340 if (results.size() > 0) {
344 selectedRegion.setT1(results[0].time);
346 selectedRegion.setT0(results[0].time);
351 trackFocus.MessageForScreenReader(message);
367 auto p = std::find_if(clips.begin(), clips.end(),
369 return clip->GetPlayStartTime() == t0; });
370 if (p != clips.end() && (*p)->GetPlayEndTime() > t1) {
372 result.startTime = (*p)->GetPlayStartTime();
373 result.endTime = (*p)->GetPlayEndTime();
374 result.name = (*p)->GetName();
375 result.index = std::distance(clips.begin(), p);
381 auto p = std::find_if(clips.begin(), clips.end(),
383 return clip->GetPlayStartTime() > t0; });
384 if (p != clips.end()) {
386 result.startTime = (*p)->GetPlayStartTime();
387 result.endTime = (*p)->GetPlayEndTime();
388 result.name = (*p)->GetName();
389 result.index = std::distance(clips.begin(), p);
409 auto p = std::find_if(clips.begin(), clips.end(),
411 return clip->GetPlayStartTime() == t0; });
412 if (p != clips.end() && (*p)->GetPlayEndTime() < t1) {
414 result.startTime = (*p)->GetPlayStartTime();
415 result.endTime = (*p)->GetPlayEndTime();
416 result.name = (*p)->GetName();
417 result.index = std::distance(clips.begin(), p);
423 auto p = std::find_if(clips.rbegin(), clips.rend(),
425 return clip->GetPlayStartTime() < t0; });
426 if (p != clips.rend()) {
428 result.startTime = (*p)->GetPlayStartTime();
429 result.endTime = (*p)->GetPlayEndTime();
430 result.name = (*p)->GetName();
432 static_cast<int>(clips.size()) - 1 -
433 std::distance(clips.rbegin(), p);
443 double t0,
double t1,
bool next, std::vector<FoundClip>& finalResults)
446 finalResults.clear();
452 std::vector<FoundClip> results;
454 int nTracksSearched = 0;
455 auto leaders =
tracks.Any();
456 auto rangeLeaders = leaders.Filter<
const WaveTrack>();
457 if (anyWaveTracksSelected)
459 for (
auto waveTrack : rangeLeaders) {
464 1 + std::distance(leaders.begin(), leaders.find(waveTrack));
465 results.push_back(result);
471 if (results.size() > 0) {
478 ? std::min_element(results.begin(), results.end(), compareStart)
479 : std::max_element(results.begin(), results.end(), compareStart);
481 std::vector<FoundClip> resultsStartTime;
482 for (
auto &r : results )
483 if ( r.startTime == (*pStart).startTime )
484 resultsStartTime.push_back( r );
486 if (resultsStartTime.size() > 1) {
490 {
return a.
endTime < b.endTime; };
492 auto pEnd = next ? std::min_element(resultsStartTime.begin(),
493 resultsStartTime.end(), compareEnd) :
494 std::max_element(resultsStartTime.begin(),
495 resultsStartTime.end(), compareEnd);
497 for (
auto &r : resultsStartTime )
498 if ( r.endTime == (*pEnd).endTime )
499 finalResults.push_back( r );
502 finalResults = resultsStartTime;
506 return nTracksSearched;
515 std::vector<FoundClip> results;
517 selectedRegion.t1(), next, results);
519 if (results.size() > 0) {
522 double t0 = results[0].startTime;
523 double t1 = results[0].endTime;
524 selectedRegion.setTimes(t0, t1);
526 window.ScrollIntoView(selectedRegion.t0());
530 for (
auto& result : results) {
531 auto longName = result.ComposeTrackName();
532 auto nClips = result.waveTrack->GetNumClips();
540 "%s, %d of %d clip %s",
541 "%s, %d of %d clips %s",
553 message =
XO(
"%s, %s").Format( message,
str );
555 trackFocus.MessageForScreenReader(message);
566 std::vector<FoundClipBoundary> results;
568 selectedRegion.t0(), next, results);
570 if (results.size() > 0) {
573 double time = results[0].time;
574 selectedRegion.setTimes(time, time);
576 window.ScrollIntoView(selectedRegion.t0());
579 trackFocus.MessageForScreenReader(message);
585 bool syncLocked,
bool right)
589 auto &selectedRegion = viewInfo.selectedRegion;
591 auto track = trackFocus.Get();
595 assert(track->IsLeader());
598 auto t0 = selectedRegion.t0();
600 std::unique_ptr<TrackShifter> uShifter;
604 if ((hitTestResult = uShifter->HitTest(t0, viewInfo)) ==
608 auto pShifter = uShifter.get();
609 auto desiredT0 = viewInfo.OffsetTimeByPixels(t0, (right ? 1 : -1));
610 auto desiredSlideAmount = pShifter->HintOffsetLarger(desiredT0 - t0);
612 state.
Init(
project, pShifter->GetTrack(), hitTestResult, move(uShifter),
613 t0, viewInfo, trackList, syncLocked);
617 double newT0 = t0 + hSlideAmount;
623 newT0 = pShifter->AdjustT0(newT0);
626 double diff = selectedRegion.duration();
627 selectedRegion.setTimes(newT0, newT0 + diff);
641 undoManager.StopConsolidating();
647 auto &selectedRegion = viewInfo.selectedRegion;
653 window.ScrollIntoView(selectedRegion.t0());
656 auto message = right?
XO(
"Moved clips to the right") :
657 XO(
"Moved clips to the left");
668 trackFocus.MessageForScreenReader(
XO(
"clip not moved"));
726 auto evt = context.
pEvt;
738 auto evt = context.
pEvt;
760 XXO(
"Pre&vious Clip Boundary to Cursor"),
764 XXO(
"Cursor to Ne&xt Clip Boundary"),
788 Command(
wxT(
"CursPrevClipBoundary"),
XXO(
"Pre&vious Clip Boundary"),
792 Command(
wxT(
"CursNextClipBoundary"),
XXO(
"Ne&xt Clip Boundary"),
801 {
wxT(
"Transport/Basic/Cursor"),
802 { OrderingHint::Before,
wxT(
"CursProjectStart") } },
820 {
wxT(
"Optional/Extra/Part1/Edit"), { OrderingHint::End, {} } },
AttachedItem sAttachment1
AttachedItem sAttachment3
AttachedItem sAttachment2
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksExistFlag()
const ReservedCommandFlag & TrackPanelHasFocus()
const TranslatableString name
XXO("&Cut/Copy/Paste Toolbar")
#define XP(sing, plur, n)
static Return Call(This &obj, Arguments ...arguments)
Invoke the method – but only after static initialization time.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectWindow & Get(AudacityProject &project)
bool IsSyncLocked() const
static SyncLockState & Get(AudacityProject &project)
bool GetSelected() const
Selectedness is always the same for all channels of a group.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
static TrackList & Get(AudacityProject &project)
@ Track
Shift selected track and sister channels only, as a whole.
@ Miss
Don't shift anything.
Holds a msgid for the translation catalog; may also bind format arguments.
static UndoManager & Get(AudacityProject &project)
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
This allows multiple clips to be a part of one WaveTrack.
A Track that contains audio waveform data.
WaveClipPointers SortedClipArray()
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
std::shared_ptr< BaseItem > BaseItemSharedPtr
CommandManager::Options Options
double DoSlideHorizontal(double desiredSlideAmount)
Do sliding of tracks and intervals, maybe adjusting the offset.
void Init(AudacityProject &project, Track &capturedTrack, TrackShifter::HitTestResult hitTestResult, std::unique_ptr< TrackShifter > pHit, double clickTime, const ViewInfo &viewInfo, TrackList &trackList, bool syncLocked)
Will associate a TrackShifter with each track in the list.
Options && WantKeyUp() &&
Options && LongName(const TranslatableString &value) &&