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"
25 auto shortName = wxString::Format(
_(
"Track %d"), trackNum).Append(
" " + waveTrack->GetName());
28 if ( waveTrack->IsLeader() )
30 return XO(
"%s left").Translation().Format(shortName);
33 return XO(
"%s right").Translation().Format(shortName);
61 bool sameClips =
false;
70 if (left.size() == right.size()) {
72 for (
unsigned int i = 0; i < left.size(); i++) {
73 if (left[i]->GetPlayStartTime() != right[i]->GetPlayStartTime() ||
74 left[i]->GetPlayEndTime() != right[i]->GetPlayEndTime()) {
88 while (!channels.empty()) {
89 auto channel = *channels.first++;
90 for (
auto other : channels) {
108 const std::vector<const WaveClip*> & clips,
double time)
110 auto q = std::find_if(clips.begin(), clips.end(),
112 return clip->GetPlayEndTime() == time; });
113 if (q != clips.end() && q + 1 != clips.end() &&
114 (*q)->SharesBoundaryWithNextClip(*(q+1))) {
115 time = (*(q+1))->GetPlayStartTime();
130 const std::vector<const WaveClip*>& clips,
double time)
132 auto q = std::find_if(clips.begin(), clips.end(),
134 return clip->GetPlayStartTime() == time; });
135 if (q != clips.end() && q != clips.begin() &&
136 (*(q - 1))->SharesBoundaryWithNextClip(*q)) {
137 time = (*(q-1))->GetPlayEndTime();
152 auto pStart = std::find_if(clips.begin(), clips.end(),
154 return clip->GetPlayStartTime() > timeStart; });
155 auto pEnd = std::find_if(clips.begin(), clips.end(),
157 return clip->GetPlayEndTime() > timeEnd; });
159 if (pStart != clips.end() && pEnd != clips.end()) {
160 if ((*pEnd)->SharesBoundaryWithNextClip(*pStart)) {
163 result.time = (*pEnd)->GetPlayEndTime();
164 result.index1 = std::distance(clips.begin(), pEnd);
165 result.name1 = (*pEnd)->GetName();
166 result.clipStart1 =
false;
167 result.index2 = std::distance(clips.begin(), pStart);
168 result.name2 = (*pStart)->GetName();
169 result.clipStart2 =
true;
171 else if ((*pStart)->GetPlayStartTime() < (*pEnd)->GetPlayEndTime()) {
173 result.time = (*pStart)->GetPlayStartTime();
174 result.index1 = std::distance(clips.begin(), pStart);
175 result.name1 = (*pStart)->GetName();
176 result.clipStart1 =
true;
180 result.time = (*pEnd)->GetPlayEndTime();
181 result.index1 = std::distance(clips.begin(), pEnd);
182 result.name1 = (*pEnd)->GetName();
183 result.clipStart1 =
false;
186 else if (pEnd != clips.end()) {
188 result.time = (*pEnd)->GetPlayEndTime();
189 result.index1 = std::distance(clips.begin(), pEnd);
190 result.name1 = (*pEnd)->GetName();
191 result.clipStart1 =
false;
205 auto pStart = std::find_if(clips.rbegin(), clips.rend(),
207 return clip->GetPlayStartTime() < timeStart; });
208 auto pEnd = std::find_if(clips.rbegin(), clips.rend(),
210 return clip->GetPlayEndTime() < timeEnd; });
212 if (pStart != clips.rend() && pEnd != clips.rend()) {
213 if ((*pEnd)->SharesBoundaryWithNextClip(*pStart)) {
216 result.time = (*pStart)->GetPlayStartTime();
218 static_cast<int>(clips.size()) - 1 -
219 std::distance(clips.rbegin(), pStart);
220 result.name1 = (*pStart)->GetName();
221 result.clipStart1 =
true;
223 static_cast<int>(clips.size()) - 1 -
224 std::distance(clips.rbegin(), pEnd);
225 result.name2 = (*pEnd)->GetName();
226 result.clipStart2 =
false;
228 else if ((*pStart)->GetPlayStartTime() > (*pEnd)->GetPlayEndTime()) {
230 result.time = (*pStart)->GetPlayStartTime();
232 static_cast<int>(clips.size()) - 1 -
233 std::distance(clips.rbegin(), pStart);
234 result.name1 = (*pStart)->GetName();
235 result.clipStart1 =
true;
239 result.time = (*pEnd)->GetPlayEndTime();
241 static_cast<int>(clips.size()) - 1 -
242 std::distance(clips.rbegin(), pEnd);
243 result.name1 = (*pEnd)->GetName();
244 result.clipStart1 =
false;
247 else if (pStart != clips.rend()) {
249 result.time = (*pStart)->GetPlayStartTime();
251 static_cast<int>(clips.size()) - 1 -
252 std::distance(clips.rbegin(), pStart);
253 result.name1 = (*pStart)->GetName();
254 result.clipStart1 =
true;
262 double time,
bool next, std::vector<FoundClipBoundary>& finalResults)
265 finalResults.clear();
267 bool anyWaveTracksSelected{ tracks.Selected<
const WaveTrack >() };
272 std::vector<FoundClipBoundary> results;
274 int nTracksSearched = 0;
275 auto leaders = tracks.Leaders();
276 auto rangeLeaders = leaders.Filter<
const WaveTrack>();
277 if (anyWaveTracksSelected)
279 for (
auto waveTrack : rangeLeaders) {
282 auto rangeChan = stereoAndDiff
286 for (
auto wt : rangeChan) {
289 if (result.nFound > 0) {
291 1 + std::distance( leaders.begin(), leaders.find( waveTrack ) );
292 result.channel = stereoAndDiff;
293 results.push_back(result);
301 if (results.size() > 0) {
305 {
return a.
time < b.time; };
307 auto p = next ? min_element(results.begin(), results.end(), compare ) :
308 max_element(results.begin(), results.end(), compare);
310 for (
auto &r : results )
311 if ( r.time == (*p).time )
312 finalResults.push_back( r );
315 return nTracksSearched;
320 const std::vector<FoundClipBoundary>& results)
323 for (
auto& result : results) {
325 auto longName = result.ComposeTrackName();
328 auto nClips = result.waveTrack->GetNumClips();
329 if (result.nFound < 2) {
341 "%s %s, %d of %d clip %s",
342 "%s %s, %d of %d clips %s",
345 result.clipStart1 ?
XO(
"start") :
XO(
"end"),
364 "%s %s and %s %s, %d and %d of %d clip %s",
365 "%s %s and %s %s, %d and %d of %d clips %s",
368 result.clipStart1 ?
XO(
"start") :
XO(
"end"),
370 result.clipStart2 ?
XO(
"start") :
XO(
"end"),
382 message =
XO(
"%s, %s").Format( message,
str );
393 std::vector<FoundClipBoundary> results;
395 selectedRegion.t0(), next, results);
397 if (results.size() > 0) {
401 selectedRegion.setT1(results[0].time);
403 selectedRegion.setT0(results[0].time);
408 trackFocus.MessageForScreenReader(message);
424 auto p = std::find_if(clips.begin(), clips.end(),
426 return clip->GetPlayStartTime() == t0; });
427 if (p != clips.end() && (*p)->GetPlayEndTime() > t1) {
429 result.startTime = (*p)->GetPlayStartTime();
430 result.endTime = (*p)->GetPlayEndTime();
431 result.name = (*p)->GetName();
432 result.index = std::distance(clips.begin(), p);
438 auto p = std::find_if(clips.begin(), clips.end(),
440 return clip->GetPlayStartTime() > t0; });
441 if (p != clips.end()) {
443 result.startTime = (*p)->GetPlayStartTime();
444 result.endTime = (*p)->GetPlayEndTime();
445 result.name = (*p)->GetName();
446 result.index = std::distance(clips.begin(), p);
466 auto p = std::find_if(clips.begin(), clips.end(),
468 return clip->GetPlayStartTime() == t0; });
469 if (p != clips.end() && (*p)->GetPlayEndTime() < t1) {
471 result.startTime = (*p)->GetPlayStartTime();
472 result.endTime = (*p)->GetPlayEndTime();
473 result.name = (*p)->GetName();
474 result.index = std::distance(clips.begin(), p);
480 auto p = std::find_if(clips.rbegin(), clips.rend(),
482 return clip->GetPlayStartTime() < t0; });
483 if (p != clips.rend()) {
485 result.startTime = (*p)->GetPlayStartTime();
486 result.endTime = (*p)->GetPlayEndTime();
487 result.name = (*p)->GetName();
489 static_cast<int>(clips.size()) - 1 -
490 std::distance(clips.rbegin(), p);
500 double t0,
double t1,
bool next, std::vector<FoundClip>& finalResults)
503 finalResults.clear();
505 bool anyWaveTracksSelected{ tracks.Selected<
const WaveTrack >() };
509 std::vector<FoundClip> results;
511 int nTracksSearched = 0;
512 auto leaders = tracks.Leaders();
513 auto rangeLeaders = leaders.Filter<
const WaveTrack>();
514 if (anyWaveTracksSelected)
516 for (
auto waveTrack : rangeLeaders) {
519 auto rangeChans = stereoAndDiff
523 for (
auto wt : rangeChans ) {
524 auto result = next ?
FindNextClip(project, wt, t0, t1) :
528 1 + std::distance( leaders.begin(), leaders.find( waveTrack ) );
529 result.channel = stereoAndDiff;
530 results.push_back(result);
538 if (results.size() > 0) {
545 ? std::min_element(results.begin(), results.end(), compareStart)
546 : std::max_element(results.begin(), results.end(), compareStart);
548 std::vector<FoundClip> resultsStartTime;
549 for (
auto &r : results )
550 if ( r.startTime == (*pStart).startTime )
551 resultsStartTime.push_back( r );
553 if (resultsStartTime.size() > 1) {
557 {
return a.
endTime < b.endTime; };
559 auto pEnd = next ? std::min_element(resultsStartTime.begin(),
560 resultsStartTime.end(), compareEnd) :
561 std::max_element(resultsStartTime.begin(),
562 resultsStartTime.end(), compareEnd);
564 for (
auto &r : resultsStartTime )
565 if ( r.endTime == (*pEnd).endTime )
566 finalResults.push_back( r );
569 finalResults = resultsStartTime;
573 return nTracksSearched;
582 std::vector<FoundClip> results;
584 selectedRegion.t1(), next, results);
586 if (results.size() > 0) {
589 double t0 = results[0].startTime;
590 double t1 = results[0].endTime;
591 selectedRegion.setTimes(t0, t1);
593 window.ScrollIntoView(selectedRegion.t0());
597 for (
auto& result : results) {
598 auto longName = result.ComposeTrackName();
599 auto nClips = result.waveTrack->GetNumClips();
607 "%s, %d of %d clip %s",
608 "%s, %d of %d clips %s",
620 message =
XO(
"%s, %s").Format( message,
str );
622 trackFocus.MessageForScreenReader(message);
633 std::vector<FoundClipBoundary> results;
635 selectedRegion.t0(), next, results);
637 if (results.size() > 0) {
640 double time = results[0].time;
641 selectedRegion.setTimes(time, time);
643 window.ScrollIntoView(selectedRegion.t0());
646 trackFocus.MessageForScreenReader(message);
652 TrackList &trackList,
bool syncLocked,
bool right )
655 auto &selectedRegion = viewInfo.selectedRegion;
660 auto t0 = selectedRegion.t0();
662 std::unique_ptr<TrackShifter> uShifter;
668 if ( (hitTestResult = uShifter->HitTest( t0, viewInfo )) ==
677 auto pShifter = uShifter.get();
678 auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
679 auto desiredSlideAmount = pShifter->HintOffsetLarger( desiredT0 - t0 );
681 state.
Init( project, pShifter->GetTrack(), hitTestResult, std::move( uShifter ),
682 t0, viewInfo, trackList, syncLocked );
686 double newT0 = t0 + hSlideAmount;
692 newT0 = pShifter->AdjustT0(newT0);
695 double diff = selectedRegion.duration();
696 selectedRegion.setTimes(newT0, newT0 + diff);
710 undoManager.StopConsolidating();
716 auto &selectedRegion = viewInfo.selectedRegion;
721 tracks, isSyncLocked, right );
723 window.ScrollIntoView(selectedRegion.t0());
726 auto message = right?
XO(
"Time shifted clips to the right") :
727 XO(
"Time shifted clips to the left");
738 trackFocus.MessageForScreenReader(
XO(
"clip not moved"));
754 auto &project = context.
project;
761 auto &project = context.
project;
767 auto &project = context.
project;
773 auto &project = context.
project;
795 auto &project = context.
project;
796 auto evt = context.
pEvt;
807 auto &project = context.
project;
808 auto evt = context.
pEvt;
830 XXO(
"Pre&vious Clip Boundary to Cursor"),
834 XXO(
"Cursor to Ne&xt Clip Boundary"),
858 Command(
wxT(
"CursPrevClipBoundary"),
XXO(
"Pre&vious Clip Boundary"),
862 Command(
wxT(
"CursNextClipBoundary"),
XXO(
"Ne&xt Clip Boundary"),
871 {
wxT(
"Transport/Basic/Cursor"),
872 { OrderingHint::Before,
wxT(
"CursProjectStart") } },
890 {
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...
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
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)
Abstract base class for an object holding data associated with points on a time axis.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
static auto SingletonRange(TrackType *pTrack) -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
@ 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()
WaveClipHolders & GetClips()
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) &&