Audacity 3.2.0
EditMenus.cpp
Go to the documentation of this file.
1
2#include "../AdornedRulerPanel.h"
3#include "../Clipboard.h"
4#include "../CommonCommandFlags.h"
5#include "../LabelTrack.h"
6#include "../Menus.h"
7#include "../NoteTrack.h"
8#include "Project.h"
9#include "ProjectHistory.h"
10#include "ProjectRate.h"
11#include "../ProjectWindow.h"
12#include "../ProjectWindows.h"
13#include "../SelectUtilities.h"
14#include "SyncLock.h"
15#include "../TrackPanel.h"
16#include "../TrackPanelAx.h"
17#include "UndoManager.h"
18#include "ViewInfo.h"
19#include "WaveTrack.h"
20#include "WaveClip.h"
21#include "SampleBlock.h"
22#include "../commands/CommandContext.h"
23#include "../commands/CommandManager.h"
24#include "TimeWarper.h"
25#include "../prefs/PrefsDialog.h"
26#include "../prefs/TracksBehaviorsPrefs.h"
27#include "../tracks/labeltrack/ui/LabelTrackView.h"
28#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
29#include "AudacityMessageBox.h"
30#include "../widgets/VetoDialogHook.h"
31#include "../AudioPasteDialog.h"
32#include "BasicUI.h"
33#include "Sequence.h"
34
35// private helper classes and functions
36namespace {
38 (const Track *n, const Track::Holder &dest, TrackList &list)
39{
40 Track::FinishCopy( n, dest.get() );
41 if (dest)
42 list.Add( dest );
43}
44
45// Handle text paste (into active label), if any. Return true if did paste.
46// (This was formerly the first part of overly-long OnPaste.)
48{
49 auto &tracks = TrackList::Get( project );
50 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
51 auto &window = ProjectWindow::Get( project );
52
53 for (auto pLabelTrack : tracks.Any<LabelTrack>())
54 {
55 // Does this track have an active label?
56 if (LabelTrackView::Get( *pLabelTrack ).GetTextEditIndex(project) != -1) {
57
58 // Yes, so try pasting into it
59 auto &view = LabelTrackView::Get( *pLabelTrack );
60 if (view.PasteSelectedText( project, selectedRegion.t0(),
61 selectedRegion.t1() ))
62 {
63 ProjectHistory::Get( project )
64 .PushState(XO("Pasted text from the clipboard"), XO("Paste"));
65
66 // Make sure caret is in view
67 int x;
68 if (view.CalcCursorX( project, &x )) {
69 window.ScrollIntoView(x);
70 }
71
72 return true;
73 }
74 }
75 }
76 return false;
77}
78
79/*
80Track copy helper function.
81When copying tracks we consider two cases when pasting:
821. There is no selection
832. Not empty region is selected
84In the first case we copy all tracks from src (used in simplified paste method
85DoPasteNothingSelected). When selection isn't empty `N = min(src.size(), dst.size())`
86tracks are copied from src, plus the last track from src could be duplicated
87`M = dst.size() - N` times more, if `M > 0` (corresponds to a paste logic after
88`!tracks.Selected()` condition in `OnPaste`). In both cases `ForEachCopiedWaveTrack`
89visits tracks that are to be copied according to behaviour described above.
90 */
92 const TrackList& dst,
93 const std::function<void(const WaveTrack& waveTrack)>& f)
94{
95 if(dst.Selected().empty())
96 {
97 for(auto waveTrack : src.Any<const WaveTrack>())
98 f(*waveTrack);
99 }
100 else
101 {
102 const auto srcTrackRange = src.Any<const WaveTrack>();
103 const auto dstTrackRange = dst.Any<const WaveTrack>();
104 auto srcTrack = srcTrackRange.begin();
105 auto dstTrack = dstTrackRange.begin();
106 auto lastCopiedTrack = srcTrack;
107 while(dstTrack != dstTrackRange.end() && srcTrack != srcTrackRange.end())
108 {
109 if(!(*dstTrack)->GetSelected())
110 {
111 ++dstTrack;
112 continue;
113 }
114
115 auto srcChannelCount = TrackList::NChannels(**srcTrack);
116 auto dstChannelCount = TrackList::NChannels(**dstTrack);
117
118 while(srcChannelCount > 0 && dstChannelCount > 0)
119 {
120 f(**srcTrack);
121
122 lastCopiedTrack = srcTrack;
123 ++srcTrack;
124 ++dstTrack;
125 --srcChannelCount;
126 --dstChannelCount;
127 }
128
129 while(dstChannelCount > 0)
130 {
131 f(**lastCopiedTrack);
132 ++dstTrack;
133 --dstChannelCount;
134 }
135 }
136 while(dstTrack != dstTrackRange.end())
137 {
138 if((*dstTrack)->GetSelected() && *lastCopiedTrack)
139 f(**lastCopiedTrack);
140 ++dstTrack;
141 }
142 }
143}
144
145wxULongLong EstimateCopyBytesCount(const TrackList& src, const TrackList& dst)
146{
147 wxULongLong result{};
148 ForEachCopiedWaveTrack(src, dst, [&](const WaveTrack& waveTrack) {
149 sampleCount samplesCount = 0;
150 for(auto& clip : waveTrack.GetClips())
151 samplesCount += clip->GetSequenceSamplesCount();
152 result += samplesCount.as_long_long() * SAMPLE_SIZE(waveTrack.GetSampleFormat());
153 });
154 return result;
155}
156
157BlockArray::size_type EstimateCopiedBlocks(const TrackList& src, const TrackList& dst)
158{
159 BlockArray::size_type result{};
160 ForEachCopiedWaveTrack(src, dst, [&](const WaveTrack& waveTrack) {
161 for(auto& clip : waveTrack.GetClips())
162 result += clip->GetSequenceBlockArray()->size();
163 });
164 return result;
165}
166
167std::shared_ptr<TrackList> DuplicateDiscardTrimmed(const TrackList& src) {
168 auto result = TrackList::Create(nullptr);
169 for(auto track : src)
170 {
171 auto trackCopy = track->Copy(track->GetStartTime(), track->GetEndTime(), false);
172 trackCopy->Init(*track);
173 trackCopy->SetOffset(track->GetStartTime());
174
175 if(auto waveTrack = dynamic_cast<WaveTrack*>(trackCopy.get()))
176 {
177 for(auto clip : waveTrack->GetClips())
178 {
179 if(clip->GetTrimLeft() != 0)
180 {
181 auto t0 = clip->GetPlayStartTime();
182 clip->SetTrimLeft(0);
183 clip->ClearLeft(t0);
184 }
185 if(clip->GetTrimRight() != 0)
186 {
187 auto t1 = clip->GetPlayEndTime();
188 clip->SetTrimRight(0);
189 clip->ClearRight(t1);
190 }
191 }
192 }
193 result->Add(trackCopy);
194 }
195 return result;
196}
197
198// Create and paste into NEW tracks.
199// Simplified version of DoPaste, used when there is no selection
200// on tracks
201// (This was formerly the second part of overly-long OnPaste.)
202void DoPasteNothingSelected(AudacityProject &project, const TrackList& src, double t0, double t1)
203{
204 auto &tracks = TrackList::Get( project );
205 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
206 auto &viewInfo = ViewInfo::Get( project );
207 auto &window = ProjectWindow::Get( project );
208
209 assert(!tracks.Selected());
210
211 Track* pFirstNewTrack = NULL;
212 for (auto pClip : src) {
213 auto pNewTrack = pClip->PasteInto( project );
214 bool newTrack = (pNewTrack.use_count() == 1);
215 wxASSERT(pClip);
216
217 if (!pFirstNewTrack)
218 pFirstNewTrack = pNewTrack.get();
219
220 pNewTrack->SetSelected(true);
221 if (newTrack)
222 FinishCopy(pClip, pNewTrack, tracks);
223 else
224 Track::FinishCopy(pClip, pNewTrack.get());
225 }
226
227 // Select some pasted samples, which is probably impossible to get right
228 // with various project and track sample rates.
229 // So do it at the sample rate of the project
230 double projRate = ProjectRate::Get( project ).GetRate();
231 double quantT0 = QUANTIZED_TIME(t0, projRate);
232 double quantT1 = QUANTIZED_TIME(t1, projRate);
233 selectedRegion.setTimes(
234 0.0, // anywhere else and this should be
235 // half a sample earlier
236 quantT1 - quantT0);
237
238 ProjectHistory::Get( project )
239 .PushState(XO("Pasted from the clipboard"), XO("Paste"));
240
241 if (pFirstNewTrack) {
242 TrackFocus::Get(project).Set(pFirstNewTrack);
243 pFirstNewTrack->EnsureVisible();
244 }
245}
246
247bool HasHiddenData(const TrackList& trackList)
248{
249 for(auto waveTrack : trackList.Any<const WaveTrack>())
250 {
251 for(auto& clip : waveTrack->GetClips())
252 {
253 if(clip->GetTrimLeft() != 0 || clip->GetTrimRight() != 0)
254 return true;
255 }
256 }
257 return false;
258}
259
260}
261
262namespace {
263
264// Menu handler functions
265
266void OnUndo(const CommandContext &context)
267{
268 auto &project = context.project;
269 auto &tracks = TrackList::Get( project );
270 auto &trackPanel = TrackPanel::Get( project );
271 auto &undoManager = UndoManager::Get( project );
272 auto &window = ProjectWindow::Get( project );
273
274 if (!ProjectHistory::Get( project ).UndoAvailable()) {
275 AudacityMessageBox( XO("Nothing to undo") );
276 return;
277 }
278
279 // can't undo while dragging
280 if (trackPanel.IsMouseCaptured()) {
281 return;
282 }
283
284 undoManager.Undo(
285 [&]( const UndoStackElem &elem ){
286 ProjectHistory::Get( project ).PopState( elem.state ); } );
287
288 auto t = *tracks.Selected().begin();
289 if (!t)
290 t = *tracks.Any().begin();
291 TrackFocus::Get(project).Set(t);
292 if (t) {
293 t->EnsureVisible();
294 }
295}
296
297void OnRedo(const CommandContext &context)
298{
299 auto &project = context.project;
300 auto &tracks = TrackList::Get( project );
301 auto &trackPanel = TrackPanel::Get( project );
302 auto &undoManager = UndoManager::Get( project );
303 auto &window = ProjectWindow::Get( project );
304
305 if (!ProjectHistory::Get( project ).RedoAvailable()) {
306 AudacityMessageBox( XO("Nothing to redo") );
307 return;
308 }
309 // Can't redo whilst dragging
310 if (trackPanel.IsMouseCaptured()) {
311 return;
312 }
313
314 undoManager.Redo(
315 [&]( const UndoStackElem &elem ){
316 ProjectHistory::Get( project ).PopState( elem.state ); } );
317
318 auto t = *tracks.Selected().begin();
319 if (!t)
320 t = *tracks.Any().begin();
321 TrackFocus::Get(project).Set(t);
322 if (t) {
323 t->EnsureVisible();
324 }
325}
326
327void OnCut(const CommandContext &context)
328{
329 auto &project = context.project;
330 auto &tracks = TrackList::Get( project );
331 auto &trackPanel = TrackPanel::Get( project );
332 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
333 auto &ruler = AdornedRulerPanel::Get( project );
334 auto &window = ProjectWindow::Get( project );
335
336 // This doesn't handle cutting labels, it handles
337 // cutting the _text_ inside of labels, i.e. if you're
338 // in the middle of editing the label text and select "Cut".
339
340 for (auto lt : tracks.Selected< LabelTrack >()) {
341 auto &view = LabelTrackView::Get( *lt );
342 if (view.CutSelectedText( context.project )) {
343 trackPanel.Refresh(false);
344 return;
345 }
346 }
347
348 //Presumably, there might be not more than one track
349 //that expects text input
350 for (auto wt : tracks.Any<WaveTrack>()) {
351 auto& view = WaveTrackView::Get(*wt);
352 if (view.CutSelectedText(context.project)) {
353 trackPanel.Refresh(false);
354 return;
355 }
356 }
357
358 auto &clipboard = Clipboard::Get();
359 clipboard.Clear();
360
361 auto pNewClipboard = TrackList::Create( nullptr );
362 auto &newClipboard = *pNewClipboard;
363
364 tracks.Selected().Visit(
365#if defined(USE_MIDI)
366 [&](NoteTrack *n) {
367 // Since portsmf has a built-in cut operator, we use that instead
368 auto dest = n->Cut(selectedRegion.t0(),
369 selectedRegion.t1());
370 FinishCopy(n, dest, newClipboard);
371 },
372#endif
373 [&](Track *n) {
374 if (n->SupportsBasicEditing()) {
375 auto dest = n->Copy(selectedRegion.t0(),
376 selectedRegion.t1());
377 FinishCopy(n, dest, newClipboard);
378 }
379 }
380 );
381
382 // Survived possibility of exceptions. Commit changes to the clipboard now.
383 clipboard.Assign(
384 std::move( newClipboard ),
385 selectedRegion.t0(),
386 selectedRegion.t1(),
387 project.shared_from_this()
388 );
389
390 // Proceed to change the project. If this throws, the project will be
391 // rolled back by the top level handler.
392
394#if defined(USE_MIDI)
395 [](NoteTrack*) {
396 //if NoteTrack, it was cut, so do not clear anything
397
398 // PRL: But what if it was sync lock selected only, not selected?
399 },
400#endif
401 [&](WaveTrack *wt, const Track::Fallthrough &fallthrough) {
402 if (gPrefs->Read(wxT("/GUI/EnableCutLines"), (long)0)) {
404 selectedRegion.t0(),
405 selectedRegion.t1());
406 }
407 else
408 fallthrough();
409 },
410 [&](Track *n) {
411 if (n->SupportsBasicEditing())
412 n->Clear(selectedRegion.t0(), selectedRegion.t1());
413 }
414 );
415
416 selectedRegion.collapseToT0();
417
418 ProjectHistory::Get( project )
419 .PushState(XO("Cut to the clipboard"), XO("Cut"));
420
421 // Bug 1663
422 //mRuler->ClearPlayRegion();
423 ruler.DrawOverlays( true );
424}
425
426void OnDelete(const CommandContext &context)
427{
428 auto &project = context.project;
429 auto &tracks = TrackList::Get( project );
430 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
431 auto &window = ProjectWindow::Get( project );
432
433 for (auto n : tracks.Any()) {
434 if (!n->SupportsBasicEditing())
435 continue;
437 n->Clear(selectedRegion.t0(), selectedRegion.t1());
438 }
439 }
440
441 double seconds = selectedRegion.duration();
442
443 selectedRegion.collapseToT0();
444
446 XO("Deleted %.2f seconds at t=%.2f")
447 .Format( seconds, selectedRegion.t0()),
448 XO("Delete"));
449}
450
451
452void OnCopy(const CommandContext &context)
453{
454 auto &project = context.project;
455 auto &tracks = TrackList::Get( project );
456 auto &trackPanel = TrackPanel::Get( project );
457 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
458
459 for (auto lt : tracks.Selected< LabelTrack >()) {
460 auto &view = LabelTrackView::Get( *lt );
461 if (view.CopySelectedText( context.project )) {
462 //trackPanel.Refresh(false);
463 return;
464 }
465 }
466 //Presumably, there might be not more than one track
467 //that expects text input
468 for (auto wt : tracks.Any<WaveTrack>()) {
469 auto& view = WaveTrackView::Get(*wt);
470 if (view.CopySelectedText(context.project)) {
471 return;
472 }
473 }
474
475 auto &clipboard = Clipboard::Get();
476 clipboard.Clear();
477
478 auto pNewClipboard = TrackList::Create( nullptr );
479 auto &newClipboard = *pNewClipboard;
480
481 for (auto n : tracks.Selected()) {
482 if (n->SupportsBasicEditing()) {
483 auto dest = n->Copy(selectedRegion.t0(),
484 selectedRegion.t1());
485 FinishCopy(n, dest, newClipboard);
486 }
487 }
488
489 // Survived possibility of exceptions. Commit changes to the clipboard now.
490 clipboard.Assign( std::move( newClipboard ),
491 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
492
493 //Make sure the menus/toolbar states get updated
494 trackPanel.Refresh(false);
495}
496
497std::pair<double, double> FindSelection(const CommandContext &context)
498{
499 double sel0 = 0.0, sel1 = 0.0;
500
501#if 0
502 // Use the overriding selection if any was given in the context
503 if (auto *pRegion = context.temporarySelection.pSelectedRegion) {
504 auto &selectedRegion = *pRegion;
505 sel0 = selectedRegion.t0();
506 sel1 = selectedRegion.t1();
507 }
508 else
509#endif
510 {
511 auto &selectedRegion = ViewInfo::Get(context.project).selectedRegion;
512 sel0 = selectedRegion.t0();
513 sel1 = selectedRegion.t1();
514 }
515
516 return { sel0, sel1 };
517}
518
519void OnPaste(const CommandContext &context)
520{
521 auto &project = context.project;
522 auto &tracks = TrackList::Get( project );
523 auto& trackPanel = TrackPanel::Get(project);
524 auto &trackFactory = WaveTrackFactory::Get( project );
525 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
526 auto &window = ProjectWindow::Get( project );
527
528 auto isSyncLocked = SyncLockState::Get(project).IsSyncLocked();
529
530 // Handle text paste (into active label) first.
531 if (DoPasteText(project))
532 return;
533
534 //Presumably, there might be not more than one track
535 //that expects text input
536 for (auto wt : tracks.Any<WaveTrack>()) {
537 auto& view = WaveTrackView::Get(*wt);
538 if (view.PasteText(context.project)) {
539 trackPanel.Refresh(false);
540 return;
541 }
542 }
543
544 const auto &clipboard = Clipboard::Get();
545 if (clipboard.GetTracks().empty())
546 return;
547
548 auto discardTrimmed = false;
549 if(&context.project != &*clipboard.Project().lock())
550 {
551 const auto waveClipCopyPolicy = TracksBehaviorsAudioTrackPastePolicy.Read();
552 if(waveClipCopyPolicy == wxT("Ask") && HasHiddenData(clipboard.GetTracks())) {
553 AudioPasteDialog audioPasteDialog(
554 &window,
555 EstimateCopyBytesCount(clipboard.GetTracks(), tracks)
556 );
557 const auto result = audioPasteDialog.ShowModal();
558 if(result == wxID_CANCEL)
559 return;
560 discardTrimmed =
562 }
563 else if(waveClipCopyPolicy == wxT("Discard"))
564 discardTrimmed = true;
565 }
566
567 std::shared_ptr<const TrackList> srcTracks;
568 if(discardTrimmed)
569 srcTracks = DuplicateDiscardTrimmed(clipboard.GetTracks());
570 else
571 srcTracks = clipboard.GetTracks().shared_from_this();
572
573 auto scopedSubscription = pSampleBlockFactory->Subscribe([
574 toCopy = EstimateCopiedBlocks(*srcTracks, tracks),
575 nCopied = 0,
576 copyStartTime = std::chrono::system_clock::now(),
577 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
578 (const SampleBlockCreateMessage&) mutable {
579 using namespace std::chrono;
580 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
581 ++nCopied;
582 if(!progressDialog) {
583 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
584 progressDialog = BasicUI::MakeProgress(XO("Paste clip"), XO("Pasting clip contents, please wait"), 0);
585 }
586 else {
587 progressDialog->Poll(nCopied, toCopy);
588 }
589 });
590
591 // If nothing's selected, we just insert NEW tracks.
592 if(!tracks.Selected())
593 {
594 DoPasteNothingSelected(project, *srcTracks, clipboard.T0(), clipboard.T1());
595 return;
596 }
597
598 // Otherwise, paste into the selected tracks.
599 double t0, t1;
600 std::tie(t0, t1) = FindSelection(context);
601
602 auto pN = tracks.Any().begin();
603
604 Track *ff = NULL;
605 const Track *lastClipBeforeMismatch = NULL;
606 const Track *mismatchedClip = NULL;
607 const Track *prevClip = NULL;
608
609 bool bAdvanceClipboard = true;
610 bool bPastedSomething = false;
611
612 auto pasteWaveTrack = [&](WaveTrack *dst, const Track *src){
613 bPastedSomething = true;
614 // For correct remapping of preserved split lines:
615 PasteTimeWarper warper{ t1, t0 + src->GetEndTime() };
616 dst->ClearAndPaste(t0, t1, src, true, true, &warper);
617 };
618
619 auto clipTrackRange = srcTracks->Any();
620 auto pC = clipTrackRange.begin();
621 size_t nnChannels=0, ncChannels=0;
622 while (*pN && *pC) {
623 auto n = *pN;
624 auto c = *pC;
625 if (n->GetSelected()) {
626 bAdvanceClipboard = true;
627 if (mismatchedClip)
628 c = mismatchedClip;
629 if (!c->SameKindAs(*n)) {
630 if (!mismatchedClip) {
631 lastClipBeforeMismatch = prevClip;
632 mismatchedClip = c;
633 }
634 bAdvanceClipboard = false;
635 c = lastClipBeforeMismatch;
636
637
638 // If the types still don't match...
639 while (c && !c->SameKindAs(*n)) {
640 prevClip = c;
641 c = * ++ pC;
642 }
643 }
644
645 // Handle case where the first track in clipboard
646 // is of different type than the first selected track
647 if (!c) {
648 c = mismatchedClip;
649 while (n && (!c->SameKindAs(*n) || !n->GetSelected()))
650 {
651 // Must perform sync-lock adjustment before incrementing n
653 auto newT1 = t0 + clipboard.Duration();
654 if (t1 != newT1 && t1 <= n->GetEndTime()) {
655 n->SyncLockAdjust(t1, newT1);
656 bPastedSomething = true;
657 }
658 }
659 n = * ++ pN;
660 }
661 if (!n)
662 c = NULL;
663 }
664
665 // The last possible case for cross-type pastes: triggered when we try
666 // to paste 1+ tracks from one type into 1+ tracks of another type. If
667 // there's a mix of types, this shouldn't run.
668 if (!c)
669 // Throw, so that any previous changes to the project in this loop
670 // are discarded.
673 XO("Pasting one type of track into another is not allowed."),
674 XO("Warning"),
675 "Error:_Copying_or_Pasting"
676 };
677
678 // We should need this check only each time we visit the leading
679 // channel
680 if ( n->IsLeader() ) {
681 wxASSERT( c->IsLeader() ); // the iteration logic should ensure this
682
683 auto ncChannels = TrackList::NChannels(*c);
684 auto nnChannels = TrackList::NChannels(*n);
685
686 // When trying to copy from stereo to mono track, show error and
687 // exit
688 // TODO: Automatically offer user to mix down to mono (unfortunately
689 // this is not easy to implement
690 if (ncChannels > nnChannels)
691 {
692 if (ncChannels > 2) {
693 // TODO: more-than-two-channels-message
694 // Re-word the error message
695 }
696 // else
697
698 // Throw, so that any previous changes to the project in this
699 // loop are discarded.
702 XO("Copying stereo audio into a mono track is not allowed."),
703 XO("Warning"),
704 "Error:_Copying_or_Pasting"
705 };
706 }
707 }
708
709 if (!ff)
710 ff = n;
711
712 wxASSERT( n && c && n->SameKindAs(*c) );
713 n->TypeSwitch(
714 [&](WaveTrack *wn){
715 pasteWaveTrack(wn, static_cast<const WaveTrack *>(c));
716 },
717 [&](LabelTrack *ln){
718 // Per Bug 293, users expect labels to move on a paste into
719 // a label track.
720 ln->Clear(t0, t1);
721
722 ln->ShiftLabelsOnInsert( clipboard.Duration(), t0 );
723
724 bPastedSomething |= ln->PasteOver(t0, c);
725 },
726 [&](Track *){
727 bPastedSomething = true;
728 n->Clear(t0, t1);
729 n->Paste(t0, c);
730 }
731 );
732
733 --nnChannels;
734 --ncChannels;
735
736 // When copying from mono to stereo track, paste the wave form
737 // to both channels
738 // TODO: more-than-two-channels
739 // This will replicate the last pasted channel as many times as needed
740 while (nnChannels > 0 && ncChannels == 0)
741 {
742 n = * ++ pN;
743 --nnChannels;
744
745 n->TypeSwitch(
746 [&](WaveTrack *wn){
747 pasteWaveTrack(wn, c);
748 },
749 [&](Track *){
750 n->Clear(t0, t1);
751 bPastedSomething = true;
752 n->Paste(t0, c);
753 }
754 );
755 }
756
757 if (bAdvanceClipboard) {
758 prevClip = c;
759 c = * ++ pC;
760 }
761 } // if (n->GetSelected())
763 {
764 auto newT1 = t0 + clipboard.Duration();
765 if (t1 != newT1 && t1 <= n->GetEndTime()) {
766 n->SyncLockAdjust(t1, newT1);
767 bPastedSomething = true;
768 }
769 }
770 ++pN;
771 }
772
773 // This block handles the cases where our clipboard is smaller
774 // than the amount of selected destination tracks. We take the
775 // last wave track, and paste that one into the remaining
776 // selected tracks.
777 if ( *pN && ! *pC )
778 {
779 const auto wc =
780 *srcTracks->Any< const WaveTrack >().rbegin();
781
782 tracks.Any().StartingWith(*pN).Visit(
783 [&](WaveTrack *wt, const Track::Fallthrough &fallthrough) {
784 if (!wt->GetSelected())
785 return fallthrough();
786
787 if (wc) {
788 pasteWaveTrack(wt, wc);
789 }
790 else {
791 auto tmp = wt->EmptyCopy( pSampleBlockFactory );
792 tmp->InsertSilence( 0.0,
793 // MJS: Is this correct?
794 clipboard.Duration() );
795 tmp->Flush();
796
797 pasteWaveTrack(wt, tmp.get());
798 }
799 },
800 [&](LabelTrack *lt, const Track::Fallthrough &fallthrough) {
802 return fallthrough();
803
804 lt->Clear(t0, t1);
805
806 // As above, only shift labels if sync-lock is on.
807 if (isSyncLocked)
809 clipboard.Duration(), t0);
810 },
811 [&](Track *n) {
813 n->SyncLockAdjust(t1, t0 + clipboard.Duration() );
814 }
815 );
816 }
817
818 // TODO: What if we clicked past the end of the track?
819
820 if (bPastedSomething)
821 {
823 .setTimes( t0, t0 + clipboard.Duration() );
824
825 ProjectHistory::Get( project )
826 .PushState(XO("Pasted from the clipboard"), XO("Paste"));
827
828 if (ff) {
829 TrackFocus::Get(project).Set(ff);
830 ff->EnsureVisible();
831 ff->LinkConsistencyFix();
832 }
833 }
834}
835
836void OnDuplicate(const CommandContext &context)
837{
838 auto &project = context.project;
839 auto &tracks = TrackList::Get( project );
840 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
841 auto &window = ProjectWindow::Get( project );
842
843 // This iteration is unusual because we add to the list inside the loop
844 auto range = tracks.Selected();
845 auto last = *range.rbegin();
846 for (auto n : range) {
847 if (!n->SupportsBasicEditing())
848 continue;
849
850 // Make copies not for clipboard but for direct addition to the project
851 auto dest = n->Copy(selectedRegion.t0(),
852 selectedRegion.t1(), false);
853 dest->Init(*n);
854 dest->SetOffset(wxMax(selectedRegion.t0(), n->GetOffset()));
855 tracks.Add( dest );
856
857 // This break is really needed, else we loop infinitely
858 if (n == last)
859 break;
860 }
861
862 ProjectHistory::Get( project )
863 .PushState(XO("Duplicated"), XO("Duplicate"));
864}
865
866void OnSplitCut(const CommandContext &context)
867{
868 auto &project = context.project;
869 auto &tracks = TrackList::Get( project );
870 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
871 auto &window = ProjectWindow::Get( project );
872
873 auto &clipboard = Clipboard::Get();
874 clipboard.Clear();
875
876 auto pNewClipboard = TrackList::Create( nullptr );
877 auto &newClipboard = *pNewClipboard;
878
879 Track::Holder dest;
880
881 tracks.Selected().Visit(
882 [&](WaveTrack *n) {
883 dest = n->SplitCut(
884 selectedRegion.t0(),
885 selectedRegion.t1());
886 if (dest)
887 FinishCopy(n, dest, newClipboard);
888 },
889 [&](Track *n) {
890 if (n->SupportsBasicEditing()) {
891 dest = n->Copy(selectedRegion.t0(),
892 selectedRegion.t1());
893 n->Silence(selectedRegion.t0(),
894 selectedRegion.t1());
895 if (dest)
896 FinishCopy(n, dest, newClipboard);
897 }
898 }
899 );
900
901 // Survived possibility of exceptions. Commit changes to the clipboard now.
902 clipboard.Assign( std::move( newClipboard ),
903 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
904
905 ProjectHistory::Get( project )
906 .PushState(XO("Split-cut to the clipboard"), XO("Split Cut"));
907}
908
909void OnSplitDelete(const CommandContext &context)
910{
911 auto &project = context.project;
912 auto &tracks = TrackList::Get( project );
913 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
914 auto &window = ProjectWindow::Get( project );
915
916 tracks.Selected().Visit(
917 [&](WaveTrack *wt) {
918 wt->SplitDelete(selectedRegion.t0(),
919 selectedRegion.t1());
920 },
921 [&](Track *n) {
922 if (n->SupportsBasicEditing())
923 n->Silence(selectedRegion.t0(),
924 selectedRegion.t1());
925 }
926 );
927
929 XO("Split-deleted %.2f seconds at t=%.2f")
930 .Format( selectedRegion.duration(), selectedRegion.t0() ),
931 XO("Split Delete"));
932}
933
934void OnSilence(const CommandContext &context)
935{
936 auto &project = context.project;
937 auto &tracks = TrackList::Get( project );
938 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
939
940 for ( auto n : tracks.Selected< WaveTrack >() )
941 n->Silence(selectedRegion.t0(), selectedRegion.t1());
942
944 XO("Silenced selected tracks for %.2f seconds at %.2f")
945 .Format( selectedRegion.duration(), selectedRegion.t0() ),
946 /* i18n-hint: verb */
947 XC("Silence", "command"));
948}
949
950void OnTrim(const CommandContext &context)
951{
952 auto &project = context.project;
953 auto &tracks = TrackList::Get( project );
954 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
955 auto &window = ProjectWindow::Get( project );
956
957 if (selectedRegion.isPoint())
958 return;
959
960 tracks.Selected().Visit(
961 [&](WaveTrack *wt) {
962 //Hide the section before the left selector
963 wt->Trim(selectedRegion.t0(),
964 selectedRegion.t1());
965 }
966 );
967
969 XO("Trim selected audio tracks from %.2f seconds to %.2f seconds")
970 .Format( selectedRegion.t0(), selectedRegion.t1() ),
971 XO("Trim Audio"));
972}
973
974void OnSplit(const CommandContext &context)
975{
976 auto &project = context.project;
977 auto &tracks = TrackList::Get( project );
978
979 auto [sel0, sel1] = FindSelection(context);
980
981 if (auto *pTrack = context.temporarySelection.pTrack) {
982 if (auto pWaveTrack = dynamic_cast<WaveTrack*>(pTrack))
983 for (auto pChannel : TrackList::Channels(pWaveTrack))
984 pChannel->Split( sel0, sel1 );
985 else
986 // Did nothing, don't push history
987 return;
988 }
989 else {
990 for (auto wt : tracks.Selected< WaveTrack >())
991 wt->Split( sel0, sel1 );
992 }
993
994 ProjectHistory::Get( project ).PushState(XO("Split"), XO("Split"));
995#if 0
996//ANSWER-ME: Do we need to keep this commented out OnSplit() code?
997// This whole section no longer used...
998 /*
999 * Previous (pre-multiclip) implementation of "Split" command
1000 * This does work only when a range is selected!
1001 *
1002 TrackListIterator iter(tracks);
1003
1004 Track *n = iter.First();
1005 Track *dest;
1006
1007 TrackList newTracks;
1008
1009 while (n) {
1010 if (n->GetSelected()) {
1011 double sel0 = selectedRegion.t0();
1012 double sel1 = selectedRegion.t1();
1013
1014 dest = n->Copy(sel0, sel1);
1015 dest->Init(*n);
1016 dest->SetOffset(wxMax(sel0, n->GetOffset()));
1017
1018 if (sel1 >= n->GetEndTime())
1019 n->Clear(sel0, sel1);
1020 else if (sel0 <= n->GetOffset()) {
1021 n->Clear(sel0, sel1);
1022 n->SetOffset(sel1);
1023 } else
1024 n->Silence(sel0, sel1);
1025
1026 newTracks.Add(dest);
1027 }
1028 n = iter.Next();
1029 }
1030
1031 TrackListIterator nIter(&newTracks);
1032 n = nIter.First();
1033 while (n) {
1034 tracks->Add(n);
1035 n = nIter.Next();
1036 }
1037
1038 PushState(XO("Split"), XO("Split"));
1039 */
1040#endif
1041}
1042
1043void OnSplitNew(const CommandContext &context)
1044{
1045 auto &project = context.project;
1046 auto &tracks = TrackList::Get( project );
1047 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
1048 auto &window = ProjectWindow::Get( project );
1049
1050 Track::Holder dest;
1051
1052 // This iteration is unusual because we add to the list inside the loop
1053 auto range = tracks.Selected();
1054 auto last = *range.rbegin();
1055 for (auto track : range) {
1056 track->TypeSwitch(
1057 [&](WaveTrack *wt) {
1058 // Clips must be aligned to sample positions or the NEW clip will
1059 // not fit in the gap where it came from
1060 double newt0 = wt->LongSamplesToTime(wt->TimeToLongSamples(
1061 selectedRegion.t0()));
1062 double newt1 = wt->LongSamplesToTime(wt->TimeToLongSamples(
1063 selectedRegion.t1()));
1064 // Fix issue 2846 by calling copy with forClipboard = false.
1065 // This avoids creating the blank placeholder clips
1066 dest = wt->Copy(newt0, newt1, false);
1067 wt->SplitDelete(newt0, newt1);
1068 if (dest) {
1069 // The copy function normally puts the clip at time 0
1070 // This offset lines it up with the original track's timing
1071 dest->Offset(newt0);
1072 FinishCopy(wt, dest, tracks);
1073 }
1074 }
1075#if 0
1076 ,
1077 // LL: For now, just skip all non-wave tracks since the other do not
1078 // yet support proper splitting.
1079 [&](Track *n) {
1080 dest = n->Cut(viewInfo.selectedRegion.t0(),
1081 viewInfo.selectedRegion.t1());
1082 if (dest) {
1083 dest->SetOffset(wxMax(0, n->GetOffset()));
1084 FinishCopy(n, dest, *tracks);
1085 }
1086 }
1087#endif
1088 );
1089 if (track == last)
1090 break;
1091 }
1092
1093 ProjectHistory::Get( project )
1094 .PushState(XO("Split to new track"), XO("Split New"));
1095}
1096
1097void OnJoin(const CommandContext &context)
1098{
1099 auto &project = context.project;
1100 auto &tracks = TrackList::Get( project );
1101 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
1102 auto &window = ProjectWindow::Get( project );
1103
1104 for (auto wt : tracks.Selected< WaveTrack >())
1105 wt->Join(selectedRegion.t0(),
1106 selectedRegion.t1());
1107
1108 ProjectHistory::Get( project ).PushState(
1109 XO("Joined %.2f seconds at t=%.2f")
1110 .Format( selectedRegion.duration(), selectedRegion.t0() ),
1111 XO("Join"));
1112}
1113
1114void OnDisjoin(const CommandContext &context)
1115{
1116 auto &project = context.project;
1117 auto &tracks = TrackList::Get( project );
1118 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
1119 auto &window = ProjectWindow::Get( project );
1120
1121 for (auto wt : tracks.Selected< WaveTrack >())
1122 wt->Disjoin(selectedRegion.t0(),
1123 selectedRegion.t1());
1124
1125 ProjectHistory::Get( project ).PushState(
1126 XO("Detached %.2f seconds at t=%.2f")
1127 .Format( selectedRegion.duration(), selectedRegion.t0() ),
1128 XO("Detach"));
1129}
1130
1131void OnPreferences(const CommandContext &context)
1132{
1133 auto &project = context.project;
1134
1135 GlobalPrefsDialog dialog(&GetProjectFrame( project ) /* parent */, &project );
1136
1137 if( VetoDialogHook::Call( &dialog ) )
1138 return;
1139
1140 if (!dialog.ShowModal()) {
1141 // Canceled
1142 return;
1143 }
1144
1145 // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with
1146 // rebuilding the menus while the PrefsDialog is still in the modal
1147 // state.
1148 for (auto p : AllProjects{}) {
1150// TODO: The comment below suggests this workaround is obsolete.
1151#if defined(__WXGTK__)
1152 // Workaround for:
1153 //
1154 // http://bugzilla.audacityteam.org/show_bug.cgi?id=458
1155 //
1156 // This workaround should be removed when Audacity updates to wxWidgets
1157 // 3.x which has a fix.
1158 auto &window = GetProjectFrame( *p );
1159 wxRect r = window.GetRect();
1160 window.SetSize(wxSize(1,1));
1161 window.SetSize(r.GetSize());
1162#endif
1163 }
1164}
1165
1166// Legacy functions, not used as of version 2.3.0
1167
1168#if 0
1169void OnPasteOver(const CommandContext &context)
1170{
1171 auto &project = context.project;
1172 auto &selectedRegion = project.GetViewInfo().selectedRegion;
1173
1174 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
1175 {
1176 selectedRegion.setT1(
1177 selectedRegion.t0() +
1178 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1179 // MJS: pointless, given what we do in OnPaste?
1180 }
1181 OnPaste(context);
1182
1183 return;
1184}
1185#endif
1186
1187// Menu definitions
1188
1191 [](const AudacityProject &project){
1192 auto range = TrackList::Get( project ).Any<const LabelTrack>()
1193 + [&](const LabelTrack *pTrack){
1194 return LabelTrackView::Get( *pTrack ).IsTextSelected(
1195 // unhappy const_cast because track focus might be set
1196 const_cast<AudacityProject&>(project)
1197 );
1198 };
1199 if ( !range.empty() )
1200 return true;
1201
1202 if (
1203 TimeSelectedPred( project )
1204 &&
1206 )
1207 return true;
1208
1209 return false;
1210 },
1212}; return flag; }
1213
1214using namespace MenuTable;
1216{
1218
1219 static const auto NotBusyTimeAndTracksFlags =
1221
1222 // The default shortcut key for Redo is different on different platforms.
1223 static constexpr auto redoKey =
1224#ifdef __WXMSW__
1225 wxT("Ctrl+Y")
1226#else
1227 wxT("Ctrl+Shift+Z")
1228#endif
1229 ;
1230
1231 // The default shortcut key for Preferences is different on different
1232 // platforms.
1233 static constexpr auto prefKey =
1234#ifdef __WXMAC__
1235 wxT("Ctrl+,")
1236#else
1237 wxT("Ctrl+P")
1238#endif
1239 ;
1240
1241 static BaseItemSharedPtr menu{
1242 Menu( wxT("Edit"), XXO("&Edit"),
1243 Section( "UndoRedo",
1244 Command( wxT("Undo"), XXO("&Undo"), OnUndo,
1245 AudioIONotBusyFlag() | UndoAvailableFlag(), wxT("Ctrl+Z") ),
1246
1247 Command( wxT("Redo"), XXO("&Redo"), OnRedo,
1248 AudioIONotBusyFlag() | RedoAvailableFlag(), redoKey ),
1249
1250 Special( wxT("UndoItemsUpdateStep"),
1251 [](AudacityProject &project, wxMenu&) {
1252 // Change names in the CommandManager as a side-effect
1254 })
1255 ),
1256
1257 Section( "Basic",
1258 // Basic Edit commands
1259 /* i18n-hint: (verb)*/
1260 Command( wxT("Cut"), XXO("Cu&t"), OnCut,
1262 wxT("Ctrl+X") ),
1263 Command( wxT("Delete"), XXO("&Delete"), OnDelete,
1265 wxT("Ctrl+K") ),
1266 /* i18n-hint: (verb)*/
1267 Command( wxT("Copy"), XXO("&Copy"), OnCopy,
1268 AudioIONotBusyFlag() | CutCopyAvailableFlag(), wxT("Ctrl+C") ),
1269 /* i18n-hint: (verb)*/
1270 Command( wxT("Paste"), XXO("&Paste"), OnPaste,
1271 AudioIONotBusyFlag(), wxT("Ctrl+V") ),
1272 /* i18n-hint: (verb)*/
1273 Command( wxT("Duplicate"), XXO("Duplic&ate"), OnDuplicate,
1274 NotBusyTimeAndTracksFlags, wxT("Ctrl+D") ),
1275
1276 Section( "",
1277 Menu( wxT("RemoveSpecial"), XXO("R&emove Special"),
1278 Section( "",
1279 /* i18n-hint: (verb) Do a special kind of cut*/
1280 Command( wxT("SplitCut"), XXO("Spl&it Cut"), OnSplitCut,
1281 NotBusyTimeAndTracksFlags,
1282 Options{ wxT("Ctrl+Alt+X") } ),
1283 /* i18n-hint: (verb) Do a special kind of DELETE*/
1284 Command( wxT("SplitDelete"), XXO("Split D&elete"), OnSplitDelete,
1285 NotBusyTimeAndTracksFlags,
1286 Options{ wxT("Ctrl+Alt+K") } )
1287 ),
1288
1289 Section( "",
1290 /* i18n-hint: (verb)*/
1291 Command( wxT("Silence"), XXO("Silence Audi&o"), OnSilence,
1293 wxT("Ctrl+L") ),
1294 /* i18n-hint: (verb)*/
1295 Command( wxT("Trim"), XXO("Tri&m Audio"), OnTrim,
1297 Options{ wxT("Ctrl+T") } )
1298 )
1299 )
1300 )
1301 ),
1302
1303
1304 Section( "Other",
1306
1307 Menu( wxT("Clip"), XXO("Audi&o Clips"),
1308 Section( "",
1309 /* i18n-hint: (verb) It's an item on a menu. */
1310 Command( wxT("Split"), XXO("Sp&lit"), OnSplit,
1312 Options{ wxT("Ctrl+I") } ),
1313 Command( wxT("SplitNew"), XXO("Split Ne&w"), OnSplitNew,
1315 Options{ wxT("Ctrl+Alt+I") } )
1316 ),
1317
1318 Section( "",
1319 /* i18n-hint: (verb)*/
1320 Command( wxT("Join"), XXO("&Join"), OnJoin,
1321 NotBusyTimeAndTracksFlags, wxT("Ctrl+J") ),
1322 Command( wxT("Disjoin"), XXO("Detac&h at Silences"), OnDisjoin,
1323 NotBusyTimeAndTracksFlags, wxT("Ctrl+Alt+J") )
1324 )
1325 )
1326
1327 ),
1328
1329 // Note that on Mac, the Preferences menu item is specially handled in
1330 // CommandManager (assigned a special wxWidgets id) so that it does
1331 // not appear in the Edit menu but instead under Audacity, consistent with
1332 // MacOS conventions.
1333 Section( "Preferences",
1334 Command( wxT("Preferences"), XXO("Pre&ferences"), OnPreferences,
1335 AudioIONotBusyFlag(), prefKey )
1336 )
1337
1338 ) };
1339 return menu;
1340}
1341
1343 wxT(""),
1345};
1346
1348{
1350 static const auto flags =
1352 static BaseItemSharedPtr menu{
1353 Menu( wxT("Edit"), XXO("&Edit"),
1354 Command( wxT("DeleteKey"), XXO("&Delete Key"), OnDelete,
1355 (flags | NoAutoSelect()),
1356 wxT("Backspace") ),
1357 Command( wxT("DeleteKey2"), XXO("Delete Key&2"), OnDelete,
1358 (flags | NoAutoSelect()),
1359 wxT("Delete") )
1360 ) };
1361 return menu;
1362}
1363
1364auto canSelectAll = [](const AudacityProject &project){
1365 return MenuManager::Get( project ).mWhatIfNoSelection != 0; };
1366auto selectAll = []( AudacityProject &project, CommandFlag flagsRqd ){
1367 if ( MenuManager::Get( project ).mWhatIfNoSelection == 1 &&
1368 (flagsRqd & NoAutoSelect()).none() )
1370};
1371
1373 []{ return TracksExistFlag(); },
1374 []{ return EditableTracksSelectedFlag(); },
1376 selectAll
1377}};
1378
1379// Including time tracks.
1381 []{ return TracksExistFlag(); },
1382 []{ return AnyTracksSelectedFlag(); },
1384 selectAll
1385}};
1386
1388 []{ return WaveTracksExistFlag(); },
1391 selectAll
1392}};
1393
1394// Also enable select for the noise reduction case.
1396 []{ return WaveTracksExistFlag(); },
1399 selectAll
1400}};
1401
1403 wxT("Optional/Extra/Part1"),
1405};
1406
1407}
wxT("CloseDown"))
@ BadUserAction
Indicates that the user performed an action that is not allowed.
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Toolkit-neutral facade for basic user interface services.
AttachedItem sAttachment1
AttachedItem sAttachment2
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:30
const ReservedCommandFlag & NoAutoSelect()
const ReservedCommandFlag & NoiseReductionTimeSelectedFlag()
bool EditableTracksSelectedPred(const AudacityProject &project)
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & UndoAvailableFlag()
const ReservedCommandFlag & RedoAvailableFlag()
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & AnyTracksSelectedFlag()
const CommandFlagOptions & cutCopyOptions()
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksExistFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
bool TimeSelectedPred(const AudacityProject &project)
@ none
Definition: Dither.h:20
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define XC(s, c)
Definition: Internat.h:37
#define QUANTIZED_TIME(time, rate)
Definition: MemoryX.h:558
FileConfig * gPrefs
Definition: Prefs.cpp:70
an object holding per-project preferred sample rate
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
#define SAMPLE_SIZE(SampleFormat)
Definition: SampleFormat.h:50
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
ChoiceSetting TracksBehaviorsAudioTrackPastePolicy
static std::once_flag flag
static AdornedRulerPanel & Get(AudacityProject &project)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
wxString Read() const
Definition: Prefs.cpp:354
static Clipboard & Get()
Definition: Clipboard.cpp:28
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
TemporarySelection temporarySelection
AudacityProject & project
Abstract base class used in importing a file.
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:87
void ShiftLabelsOnInsert(double length, double pt)
Definition: LabelTrack.cpp:226
void Clear(double t0, double t1) override
Definition: LabelTrack.cpp:177
static LabelTrackView & Get(LabelTrack &)
bool IsTextSelected(AudacityProject &project) const
int GetTextEditIndex(AudacityProject &project) const
void RebuildMenuBar(AudacityProject &project)
Definition: Menus.cpp:497
int mWhatIfNoSelection
Definition: Menus.h:124
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:69
static void ModifyUndoMenuItems(AudacityProject &project)
Definition: Menus.cpp:455
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:63
Track::Holder Cut(double t0, double t1) override
Definition: NoteTrack.cpp:443
void Clear(double t0, double t1) override
Definition: NoteTrack.cpp:520
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Definition: NoteTrack.cpp:473
bool setTimes(double t0, double t1)
Definition: ViewInfo.cpp:51
double t0() const
Definition: ViewInfo.h:35
Unit slope but with either a jump (pasting more) or a flat interval (pasting less)
Definition: TimeWarper.h:181
int ShowModal() override
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void PopState(const UndoState &state, bool doAutosave=true)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
static ProjectWindow & Get(AudacityProject &project)
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
Definition: SampleTrack.cpp:48
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:43
A MessageBoxException that shows a given, unvarying string.
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:112
static bool IsSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:82
bool IsSyncLocked() const
Definition: SyncLock.cpp:43
static SyncLockState & Get(AudacityProject &project)
Definition: SyncLock.cpp:26
Track * Get()
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:162
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:98
virtual void SetSelected(bool s)
Definition: Track.cpp:87
virtual Holder PasteInto(AudacityProject &) const =0
Find or create the destination track for a paste, maybe in a different project.
static void FinishCopy(const Track *n, Track *dest)
Definition: Track.cpp:314
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
Definition: Track.cpp:1166
virtual void SyncLockAdjust(double oldT1, double newT1)
Definition: Track.cpp:281
std::shared_ptr< Track > Holder
Definition: Track.h:303
Continuation<> Fallthrough
Type of arguments passed as optional second parameter to TypeSwitch<void>() cases.
Definition: Track.h:470
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1212
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:401
static size_t NChannels(const Track &track)
Count channels of a track.
Definition: Track.h:1424
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
Definition: Track.h:1446
size_t size() const
Definition: Track.cpp:922
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1313
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:385
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1330
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1417
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:231
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:219
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2606
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
void SplitDelete(double t0, double t1)
Definition: WaveTrack.cpp:1031
sampleFormat GetSampleFormat() const override
Definition: WaveTrack.h:151
void Silence(double t0, double t1) override
Definition: WaveTrack.cpp:1437
void ClearAndAddCutLine(double t0, double t1)
Definition: WaveTrack.cpp:719
void Trim(double t0, double t1)
Definition: WaveTrack.cpp:603
WaveClipHolders & GetClips()
Definition: WaveTrack.h:322
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:771
Track::Holder SplitCut(double t0, double t1)
Definition: WaveTrack.cpp:570
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Definition: WaveTrack.cpp:646
static WaveTrackView & Get(WaveTrack &track)
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
long long as_long_long() const
Definition: SampleCount.h:48
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
Definition: BasicUI.h:289
constexpr auto Special
constexpr auto Section
constexpr auto Menu
constexpr auto Command
void Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItemBase *pRegistry)
Definition: Registry.cpp:737
std::unique_ptr< IndirectItem > Indirect(const BaseItemSharedPtr &ptr)
A convenience function.
Definition: Registry.h:97
std::shared_ptr< BaseItem > BaseItemSharedPtr
Definition: Registry.h:74
void DoSelectAllAudio(AudacityProject &project)
wxULongLong EstimateCopyBytesCount(const TrackList &src, const TrackList &dst)
Definition: EditMenus.cpp:145
BlockArray::size_type EstimateCopiedBlocks(const TrackList &src, const TrackList &dst)
Definition: EditMenus.cpp:157
void OnDisjoin(const CommandContext &context)
Definition: EditMenus.cpp:1114
void DoPasteNothingSelected(AudacityProject &project, const TrackList &src, double t0, double t1)
Definition: EditMenus.cpp:202
bool DoPasteText(AudacityProject &project)
Definition: EditMenus.cpp:47
void OnRedo(const CommandContext &context)
Definition: EditMenus.cpp:297
void OnJoin(const CommandContext &context)
Definition: EditMenus.cpp:1097
RegisteredMenuItemEnabler selectWaveTracks
Definition: EditMenus.cpp:1387
std::shared_ptr< TrackList > DuplicateDiscardTrimmed(const TrackList &src)
Definition: EditMenus.cpp:167
void FinishCopy(const Track *n, const Track::Holder &dest, TrackList &list)
Definition: EditMenus.cpp:38
RegisteredMenuItemEnabler selectTracks
Definition: EditMenus.cpp:1372
void OnDelete(const CommandContext &context)
Definition: EditMenus.cpp:426
void OnPaste(const CommandContext &context)
Definition: EditMenus.cpp:519
const ReservedCommandFlag & CutCopyAvailableFlag()
Definition: EditMenus.cpp:1190
void OnSplit(const CommandContext &context)
Definition: EditMenus.cpp:974
std::pair< double, double > FindSelection(const CommandContext &context)
Definition: EditMenus.cpp:497
void OnSilence(const CommandContext &context)
Definition: EditMenus.cpp:934
RegisteredMenuItemEnabler selectWaveTracks2
Definition: EditMenus.cpp:1395
void OnTrim(const CommandContext &context)
Definition: EditMenus.cpp:950
void OnSplitDelete(const CommandContext &context)
Definition: EditMenus.cpp:909
void ForEachCopiedWaveTrack(const TrackList &src, const TrackList &dst, const std::function< void(const WaveTrack &waveTrack)> &f)
Definition: EditMenus.cpp:91
void OnCopy(const CommandContext &context)
Definition: EditMenus.cpp:452
void OnUndo(const CommandContext &context)
Definition: EditMenus.cpp:266
void OnSplitCut(const CommandContext &context)
Definition: EditMenus.cpp:866
void OnPreferences(const CommandContext &context)
Definition: EditMenus.cpp:1131
void OnDuplicate(const CommandContext &context)
Definition: EditMenus.cpp:836
RegisteredMenuItemEnabler selectAnyTracks
Definition: EditMenus.cpp:1380
bool HasHiddenData(const TrackList &trackList)
Definition: EditMenus.cpp:247
BaseItemSharedPtr ExtraEditMenu()
Definition: EditMenus.cpp:1347
void OnSplitNew(const CommandContext &context)
Definition: EditMenus.cpp:1043
void OnCut(const CommandContext &context)
Definition: EditMenus.cpp:327
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.
Definition: UndoManager.h:117
UndoState state
Definition: UndoManager.h:128