Audacity 3.2.0
EditMenus.cpp
Go to the documentation of this file.
1#include "../AdornedRulerPanel.h"
2#include "../Clipboard.h"
3#include "../CommonCommandFlags.h"
4#include "../LabelTrack.h"
5#include "../MenuCreator.h"
6#include "NoteTrack.h"
7#include "Project.h"
8#include "ProjectHistory.h"
9#include "ProjectRate.h"
11#include "../ProjectWindows.h"
12#include "../ProjectWindows.h"
13#include "../SelectUtilities.h"
14#include "SyncLock.h"
15#include "../TrackPanel.h"
16#include "TrackFocus.h"
17#include "UndoManager.h"
18#include "ViewInfo.h"
19#include "WaveTrack.h"
20#include "WaveTrackUtilities.h"
21#include "WaveClip.h"
22#include "SampleBlock.h"
23#include "CommandContext.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/WaveChannelView.h"
29#include "AudacityMessageBox.h"
30#include "../AudioPasteDialog.h"
31#include "BasicUI.h"
32#include "Sequence.h"
33#include "UserException.h"
34#include "Viewport.h"
35
36#include <wx/frame.h>
37
38// private helper classes and functions
39namespace {
40
41// Handle text paste. Return true if did paste.
42// (This was formerly the first part of overly-long OnPaste.)
44{
45 auto &tracks = TrackList::Get( project );
46 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
47 auto &viewport = Viewport::Get(project);
48
49 // Paste into the active label (if any)
50 for (auto pLabelTrack : tracks.Any<LabelTrack>()) {
51 // Does this track have an active label?
52 if (LabelTrackView::Get( *pLabelTrack ).GetTextEditIndex(project) != -1) {
53
54 // Yes, so try pasting into it
55 auto &view = LabelTrackView::Get( *pLabelTrack );
56 if (view.PasteSelectedText( project, selectedRegion.t0(),
57 selectedRegion.t1() ))
58 {
60 .PushState(XO("Pasted text from the clipboard"), XO("Paste"));
61
62 // Make sure caret is in view
63 int x;
64 if (view.CalcCursorX( project, &x )) {
65 viewport.ScrollIntoView(x);
66 }
67
68 return true;
69 }
70 }
71 }
72
73 //Presumably, there might be not more than one track
74 //that expects text input
75 for (auto wt : tracks.Any<WaveTrack>()) {
76 auto& view = WaveChannelView::Get(*wt);
77 if (view.PasteText(project)) {
78 auto &trackPanel = TrackPanel::Get(project);
79 trackPanel.Refresh(false);
80 return true;
81 }
82 }
83
84 return false;
85}
86
87wxULongLong EstimateCopyBytesCount(const TrackList& src, const TrackList& dst)
88{
89 wxULongLong result{};
90 for (auto waveTrack : src.Any<const WaveTrack>()) {
91 const auto samplesCount = waveTrack->GetSequenceSamplesCount();
92 result += samplesCount.as_long_long() *
93 SAMPLE_SIZE(waveTrack->GetSampleFormat());
94 }
95 return result;
96}
97
98BlockArray::size_type EstimateCopiedBlocks(const TrackList& src, const TrackList& dst)
99{
100 BlockArray::size_type result{};
101 for (const auto waveTrack : src.Any<const WaveTrack>())
102 result += waveTrack->CountBlocks();
103 return result;
104}
105
106std::shared_ptr<TrackList> DuplicateDiscardTrimmed(const TrackList& src) {
107 auto result = TrackList::Create(nullptr);
108 for (auto track : src) {
109 const auto copies =
110 track->Copy(track->GetStartTime(), track->GetEndTime(), false);
111 const auto pTrack = *copies->begin();
112 pTrack->MoveTo(track->GetStartTime());
113 if (const auto waveTrack = dynamic_cast<WaveTrack*>(pTrack))
114 waveTrack->DiscardTrimmed();
115 result->Append(std::move(*copies));
116 }
117 return result;
118}
119
120// Create and paste into NEW tracks.
121// Simplified version of DoPaste, used when there is no selection
122// on tracks
123// (This was formerly the second part of overly-long OnPaste.)
124void DoPasteNothingSelected(AudacityProject &project, const TrackList& src, double t0, double t1)
125{
126 auto &tracks = TrackList::Get( project );
127 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
128 auto &viewInfo = ViewInfo::Get( project );
129
130 assert(tracks.Selected().empty());
131
132 Track* pFirstNewTrack = NULL;
133 for (auto pClip : src) {
134 auto pNewTrack = pClip->PasteInto(project, tracks);
135 if (!pFirstNewTrack)
136 pFirstNewTrack = pNewTrack.get();
137 pNewTrack->SetSelected(true);
138 }
139
140 // Select some pasted samples, which is probably impossible to get right
141 // with various project and track sample rates.
142 // So do it at the sample rate of the project
143 const double projRate = ProjectRate::Get( project ).GetRate();
144 const double projTempo = ProjectTimeSignature::Get(project).GetTempo();
145 const double srcTempo =
146 pFirstNewTrack ? pFirstNewTrack->GetProjectTempo().value_or(projTempo) :
147 projTempo;
148 // Apply adequate stretching to the selection. A selection of 10 seconds of
149 // audio in project A should become 5 seconds in project B if tempo in B is
150 // twice as fast.
151 const double quantT0 = QUANTIZED_TIME(t0 * srcTempo / projTempo, projRate);
152 const double quantT1 = QUANTIZED_TIME(t1 * srcTempo / projTempo, projRate);
153 selectedRegion.setTimes(
154 0.0, // anywhere else and this should be
155 // half a sample earlier
156 quantT1 - quantT0);
157
159 .PushState(XO("Pasted from the clipboard"), XO("Paste"));
160
161 if (pFirstNewTrack) {
162 TrackFocus::Get(project).Set(pFirstNewTrack);
163 Viewport::Get(project).ShowTrack(*pFirstNewTrack);
164 }
165}
166
167bool HasHiddenData(const TrackList& trackList)
168{
169 const auto range = trackList.Any<const WaveTrack>();
170 return std::any_of(range.begin(), range.end(),
171 [](const WaveTrack *pTrack){ return pTrack->HasHiddenData(); });
172}
173
174// Menu handler functions
175
176void OnUndo(const CommandContext &context)
177{
178 auto &project = context.project;
179 auto &tracks = TrackList::Get( project );
180 auto &trackPanel = TrackPanel::Get( project );
181 auto &undoManager = UndoManager::Get( project );
182
183 if (!ProjectHistory::Get( project ).UndoAvailable()) {
184 AudacityMessageBox( XO("Nothing to undo") );
185 return;
186 }
187
188 // can't undo while dragging
189 if (trackPanel.IsMouseCaptured()) {
190 return;
191 }
192
193 undoManager.Undo(
194 [&]( const UndoStackElem &elem ){
196
197 auto t = *tracks.Selected().begin();
198 if (!t)
199 t = *tracks.begin();
200 TrackFocus::Get(project).Set(t);
201 if (t)
203}
204
205void OnRedo(const CommandContext &context)
206{
207 auto &project = context.project;
208 auto &tracks = TrackList::Get( project );
209 auto &trackPanel = TrackPanel::Get( project );
210 auto &undoManager = UndoManager::Get( project );
211
212 if (!ProjectHistory::Get( project ).RedoAvailable()) {
213 AudacityMessageBox( XO("Nothing to redo") );
214 return;
215 }
216 // Can't redo whilst dragging
217 if (trackPanel.IsMouseCaptured()) {
218 return;
219 }
220
221 undoManager.Redo(
222 [&]( const UndoStackElem &elem ){
224
225 auto t = *tracks.Selected().begin();
226 if (!t)
227 t = *tracks.begin();
228 TrackFocus::Get(project).Set(t);
229 if (t)
231}
232
233void OnCut(const CommandContext &context)
234{
235 auto &project = context.project;
236 auto &tracks = TrackList::Get( project );
237 auto &trackPanel = TrackPanel::Get( project );
238 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
240
241 // This doesn't handle cutting labels, it handles
242 // cutting the _text_ inside of labels, i.e. if you're
243 // in the middle of editing the label text and select "Cut".
244
245 for (auto lt : tracks.Selected<LabelTrack>()) {
246 auto &view = LabelTrackView::Get( *lt );
247 if (view.CutSelectedText( context.project )) {
248 trackPanel.Refresh(false);
249 return;
250 }
251 }
252
253 //Presumably, there might be not more than one track
254 //that expects text input
255 for (auto wt : tracks.Any<WaveTrack>()) {
256 auto& view = WaveChannelView::Get(*wt);
257 if (view.CutSelectedText(context.project)) {
258 trackPanel.Refresh(false);
259 return;
260 }
261 }
262
263 auto &clipboard = Clipboard::Get();
264 clipboard.Clear();
265
266 auto pNewClipboard = TrackList::Create( nullptr );
267 auto &newClipboard = *pNewClipboard;
268
269 tracks.Selected().Visit(
270#if defined(USE_MIDI)
271 [&](NoteTrack &n) {
272 // Since portsmf has a built-in cut operator, we use that instead
273 auto dest = n.Cut(selectedRegion.t0(), selectedRegion.t1());
274 newClipboard.Append(std::move(*dest));
275 },
276#endif
277 [&](Track &n) {
278 if (n.SupportsBasicEditing()) {
279 auto dest = n.Copy(selectedRegion.t0(), selectedRegion.t1());
280 newClipboard.Append(std::move(*dest));
281 }
282 }
283 );
284
285 // Survived possibility of exceptions. Commit changes to the clipboard now.
286 clipboard.Assign(
287 std::move( newClipboard ),
288 selectedRegion.t0(),
289 selectedRegion.t1(),
290 project.shared_from_this()
291 );
292
293 // Proceed to change the project. If this throws, the project will be
294 // rolled back by the top level handler.
295
297#if defined(USE_MIDI)
298 [](NoteTrack&) {
299 //if NoteTrack, it was cut, so do not clear anything
300
301 // PRL: But what if it was sync lock selected only, not selected?
302 },
303#endif
304 [&](auto &&fallthrough){ return [&](WaveTrack &wt) {
305 if (gPrefs->Read(wxT("/GUI/EnableCutLines"), (long)0))
306 wt.ClearAndAddCutLine(selectedRegion.t0(), selectedRegion.t1());
307 else
308 fallthrough();
309 }; },
310 [&](Track &n) {
311 if (n.SupportsBasicEditing())
312 n.Clear(selectedRegion.t0(), selectedRegion.t1());
313 }
314 );
315
316 selectedRegion.collapseToT0();
317
319 .PushState(XO("Cut to the clipboard"), XO("Cut"));
320
321 // Bug 1663
322 //mRuler->ClearPlayRegion();
323 ruler.DrawOverlays( true );
324}
325
326void OnDelete(const CommandContext &context)
327{
328 auto &project = context.project;
329 auto &tracks = TrackList::Get( project );
330 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
331
332 for (auto n : tracks) {
333 if (!n->SupportsBasicEditing())
334 continue;
336 n->Clear(selectedRegion.t0(), selectedRegion.t1());
337 }
338 }
339
340 double seconds = selectedRegion.duration();
341
342 selectedRegion.collapseToT0();
343
345 XO("Deleted %.2f seconds at t=%.2f")
346 .Format( seconds, selectedRegion.t0()),
347 XO("Delete"));
348}
349
350
351void OnCopy(const CommandContext &context)
352{
353 auto &project = context.project;
354 auto &tracks = TrackList::Get( project );
355 auto &trackPanel = TrackPanel::Get( project );
356 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
357
358 for (auto lt : tracks.Selected<LabelTrack>()) {
359 auto &view = LabelTrackView::Get( *lt );
360 if (view.CopySelectedText( context.project )) {
361 //trackPanel.Refresh(false);
362 return;
363 }
364 }
365 //Presumably, there might be not more than one track
366 //that expects text input
367 for (auto wt : tracks.Any<WaveTrack>()) {
368 auto& view = WaveChannelView::Get(*wt);
369 if (view.CopySelectedText(context.project)) {
370 return;
371 }
372 }
373
374 auto &clipboard = Clipboard::Get();
375 clipboard.Clear();
376
377 auto pNewClipboard = TrackList::Create( nullptr );
378 auto &newClipboard = *pNewClipboard;
379
380 for (auto n : tracks.Selected()) {
381 if (n->SupportsBasicEditing()) {
382 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1());
383 newClipboard.Append(std::move(*dest));
384 }
385 }
386
387 // Survived possibility of exceptions. Commit changes to the clipboard now.
388 clipboard.Assign( std::move( newClipboard ),
389 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
390
391 //Make sure the menus/toolbar states get updated
392 trackPanel.Refresh(false);
393}
394
395std::pair<double, double> FindSelection(const CommandContext &context)
396{
397 double sel0 = 0.0, sel1 = 0.0;
398
399#if 0
400 // Use the overriding selection if any was given in the context
401 if (auto *pRegion = context.temporarySelection.pSelectedRegion) {
402 auto &selectedRegion = *pRegion;
403 sel0 = selectedRegion.t0();
404 sel1 = selectedRegion.t1();
405 }
406 else
407#endif
408 {
409 auto &selectedRegion = ViewInfo::Get(context.project).selectedRegion;
410 sel0 = selectedRegion.t0();
411 sel1 = selectedRegion.t1();
412 }
413
414 return { sel0, sel1 };
415}
416
417std::shared_ptr<const TrackList> FindSourceTracks(const CommandContext &context)
418{
419 auto &project = context.project;
420 auto &window = GetProjectFrame(project);
422 const auto &clipboard = Clipboard::Get();
423 auto discardTrimmed = false;
424 if (&context.project != &*clipboard.Project().lock()) {
425 const auto waveClipCopyPolicy = TracksBehaviorsAudioTrackPastePolicy.Read();
426 if(waveClipCopyPolicy == wxT("Ask") && HasHiddenData(clipboard.GetTracks())) {
427 AudioPasteDialog audioPasteDialog(
428 &window,
429 EstimateCopyBytesCount(clipboard.GetTracks(), tracks)
430 );
431 const auto result = audioPasteDialog.ShowModal();
432 if(result == wxID_CANCEL)
433 return {};
434 discardTrimmed =
436 }
437 else if(waveClipCopyPolicy == wxT("Discard"))
438 discardTrimmed = true;
439 }
440
441 std::shared_ptr<const TrackList> srcTracks;
442 if(discardTrimmed)
443 srcTracks = DuplicateDiscardTrimmed(clipboard.GetTracks());
444 else
445 srcTracks = clipboard.GetTracks().shared_from_this();
446
447 return srcTracks;
448}
449
451 const CommandContext &context, const TrackList &srcTracks)
452{
453 auto &project = context.project;
455 auto &trackFactory = WaveTrackFactory::Get(project);
456 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
457 return pSampleBlockFactory->Subscribe([
458 toCopy = EstimateCopiedBlocks(srcTracks, tracks),
459 nCopied = 0,
460 copyStartTime = std::chrono::system_clock::now(),
461 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
462 (const SampleBlockCreateMessage&) mutable {
463 using namespace std::chrono;
464 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
465 ++nCopied;
466 if(!progressDialog) {
467 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
468 progressDialog = BasicUI::MakeProgress(XO("Paste clip"), XO("Pasting clip contents, please wait"), 0);
469 }
470 else {
471 progressDialog->Poll(nCopied, toCopy);
472 }
473 });
474}
475
477bool FitsInto(const Track &src, const Track &dst)
478{
479 if (!src.SameKindAs(dst))
480 return false;
481 // Mono can "fit" into stereo, by duplication of the channel
482 // Otherwise non-wave tracks always have just one "channel"
483 // Future: Fit stereo into mono too, using mix-down
484 return TrackList::NChannels(src) <= TrackList::NChannels(dst);
485}
486
487// First, destination track; second, source
488using Correspondence = std::vector<std::pair<Track*, const Track*>>;
489
491 TrackList &dstTracks, const TrackList &srcTracks)
492{
493 Correspondence result;
494 auto dstRange = dstTracks.Selected();
495 if (dstRange.size() == 1)
496 // Special rule when only one track is selected interprets the user's
497 // intent as pasting into that track and following ones
498 dstRange = dstTracks.Any().StartingWith(*dstRange.begin());
499 auto srcRange = srcTracks.Any();
500 while (!(dstRange.empty() || srcRange.empty())) {
501 auto &dst = **dstRange.begin();
502 auto &src = **srcRange.begin();
503 if (!FitsInto(src, dst)) {
504 // Skip selected track of inappropriate type and try again
505 ++dstRange.first;
506 continue;
507 }
508 result.emplace_back(&dst, &src);
509 ++srcRange.first;
510 ++dstRange.first;
511 }
512
513 if (!srcRange.empty())
514 // Could not fit all source tracks into the selected tracks
515 return {};
516 else
517 return result;
518}
519
520void OnPaste(const CommandContext &context)
521{
522 auto &project = context.project;
523
524 // Handle text paste first.
525 if (DoPasteText(project))
526 return;
527
528 const auto &clipboard = Clipboard::Get();
529 if (clipboard.GetTracks().empty())
530 return;
531
532 const auto srcTracks = FindSourceTracks(context);
533 if (!srcTracks)
534 // user cancelled
535 return;
536
537 auto notificationScope = NotificationScope(context, *srcTracks);
538
540 // If nothing's selected, we just insert new tracks.
541 if (!tracks.Selected()) {
543 project, *srcTracks, clipboard.T0(), clipboard.T1());
544 return;
545 }
546
547 // Otherwise, paste into the selected tracks.
548 double t0, t1;
549 std::tie(t0, t1) = FindSelection(context);
550 auto newT1 = t0 + clipboard.Duration();
551 const auto isSyncLocked = SyncLockState::Get(project).IsSyncLocked();
552
553 Track *ff = nullptr;
554 bool bPastedSomething = false;
555
556 // Find tracks to paste in
557 auto correspondence = FindCorrespondence(tracks, *srcTracks);
558 if (correspondence.empty()) {
559 if (tracks.Selected().size() == 1)
561"The content you are trying to paste will span across more tracks than you "
562"currently have available. Add more tracks and try again.")
563 );
564 else
566"There are not enough tracks selected to accommodate your copied content. "
567"Select additional tracks and try again.")
568 );
569 return;
570 }
571 auto iPair = correspondence.begin();
572 const auto endPair = correspondence.cend();
573
574 // Outer loop by sync-lock groups
575 auto next = tracks.begin();
576 for (auto range = tracks.Any(); !range.empty();
577 // Skip to next sync lock group
578 range.first = next
579 ) {
580 if (iPair == endPair)
581 // Nothing more to paste
582 break;
583 auto group = SyncLock::Group(*range.first);
584 next = tracks.Find(*group.rbegin());
585 ++next;
586
587 if (!group.contains(iPair->first))
588 // Nothing to paste into this group
589 continue;
590
591 // Inner loop over the group by tracks (not channels)
592 for (auto leader : group) {
593 if (iPair == endPair || leader != iPair->first) {
594 if (isSyncLocked) {
595 // Track is not pasted into but must be adjusted
596 if (t1 != newT1 && t1 <= leader->GetEndTime()) {
597 leader->SyncLockAdjust(t1, newT1);
598 bPastedSomething = true;
599 }
600 }
601 }
602 else {
603 // Remember first pasted-into track, to focus it
604 if (!ff)
605 ff = leader;
606 // Do the pasting!
607 const auto src = (iPair++)->second;
608 leader->TypeSwitch(
609 [&](WaveTrack &wn){
610 bPastedSomething = true;
611 // For correct remapping of preserved split lines:
612 PasteTimeWarper warper{ t1, t0 + src->GetEndTime() };
613 const auto newClipOnPaste =
614 gPrefs->ReadBool(wxT("/GUI/PasteAsNewClips"), false);
615 // The new-clip-on-paste behavior means: not merging the
616 // clipboard data with data at the selection borders; not
617 // reproducing boundaries within the selected region in the
618 // new clip; preserving the data underneath by trimming
619 // (rather than deleting).
620 // The legacy behavior is the opposite.
621 const auto merge = newClipOnPaste ? false : true;
622 const auto preserveExistingBoundaries = newClipOnPaste ? false : true;
623 auto clearByTrimming = newClipOnPaste ? true : false;
624 wn.ClearAndPaste(
625 t0, t1, *static_cast<const WaveTrack*>(src),
626 preserveExistingBoundaries, merge, &warper,
627 clearByTrimming);
628 },
629 [&](LabelTrack &ln){
630 // Per Bug 293, users expect labels to move on a paste into
631 // a label track.
632 ln.Clear(t0, t1);
633
634 ln.ShiftLabelsOnInsert( clipboard.Duration(), t0 );
635
636 bPastedSomething |= ln.PasteOver(t0, *src);
637 },
638 [&](Track &t){
639 bPastedSomething = true;
640 t.Clear(t0, t1);
641 t.Paste(t0, *src);
642 }
643 );
644 }
645 }
646 }
647
648 // TODO: What if we clicked past the end of the track?
649
650 if (bPastedSomething) {
652 .setTimes( t0, t0 + clipboard.Duration() );
653
655 .PushState(XO("Pasted from the clipboard"), XO("Paste"));
656
657 if (ff) {
658 TrackFocus::Get(project).Set(ff);
660 }
661 }
662}
663
664void OnDuplicate(const CommandContext &context)
665{
666 auto &project = context.project;
668 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
669
670 // This iteration is unusual because we add to the list inside the loop
671 auto range = tracks.Selected();
672 auto last = *range.rbegin();
673 for (auto n : range) {
674 if (!n->SupportsBasicEditing())
675 continue;
676
677 // Make copies not for clipboard but for direct addition to the project
678 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1(), false);
679 (*dest->begin())
680 ->MoveTo(std::max(selectedRegion.t0(), n->GetStartTime()));
681 tracks.Append(std::move(*dest));
682
683 // This break is really needed, else we loop infinitely
684 if (n == last)
685 break;
686 }
687
689 .PushState(XO("Duplicated"), XO("Duplicate"));
690}
691
692void OnSplitCut(const CommandContext &context)
693{
694 auto &project = context.project;
696 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
697
698 auto &clipboard = Clipboard::Get();
699 clipboard.Clear();
700
701 auto pNewClipboard = TrackList::Create(nullptr);
702 auto &newClipboard = *pNewClipboard;
703
704 tracks.Selected().Visit(
705 [&](WaveTrack &n) {
706 auto tracks = n.SplitCut(selectedRegion.t0(), selectedRegion.t1());
707 newClipboard.Append(std::move(*tracks));
708 },
709 [&](Track &n) {
710 if (n.SupportsBasicEditing()) {
711 auto dest = n.Copy(selectedRegion.t0(), selectedRegion.t1());
712 n.Silence(selectedRegion.t0(), selectedRegion.t1());
713 newClipboard.Append(std::move(*dest));
714 }
715 }
716 );
717
718 // Survived possibility of exceptions. Commit changes to the clipboard now.
719 clipboard.Assign(std::move(newClipboard),
720 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this());
721
723 .PushState(XO("Split-cut to the clipboard"), XO("Split Cut"));
724}
725
726void OnSplitDelete(const CommandContext &context)
727{
728 auto &project = context.project;
730 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
731
732 tracks.Selected().Visit(
733 [&](WaveTrack &wt) {
734 wt.SplitDelete(selectedRegion.t0(), selectedRegion.t1());
735 },
736 [&](Track &n) {
737 if (n.SupportsBasicEditing())
738 n.Silence(selectedRegion.t0(), selectedRegion.t1());
739 }
740 );
741
743 XO("Split-deleted %.2f seconds at t=%.2f")
744 .Format(selectedRegion.duration(), selectedRegion.t0()),
745 XO("Split Delete"));
746}
747
748void OnSilence(const CommandContext &context)
749{
750 auto &project = context.project;
752 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
753
754 const auto selectedWaveTracks = tracks.Selected<WaveTrack>();
756 [&](const ProgressReporter& parent) {
758 selectedWaveTracks.begin(), selectedWaveTracks.end(),
759 [&](WaveTrack* n, const ProgressReporter& child) {
760 n->Silence(selectedRegion.t0(), selectedRegion.t1(), child);
761 },
762 parent);
763 });
764
766 XO("Silenced selected tracks for %.2f seconds at %.2f")
767 .Format(selectedRegion.duration(), selectedRegion.t0()),
768 /* i18n-hint: verb */
769 XC("Silence", "command"));
770}
771
772void OnTrim(const CommandContext &context)
773{
774 auto &project = context.project;
775 auto &tracks = TrackList::Get( project );
776 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
777
778 if (selectedRegion.isPoint())
779 return;
780
781 tracks.Selected().Visit( [&](WaveTrack &wt) {
782 //Hide the section before the left selector
783 wt.Trim(selectedRegion.t0(), selectedRegion.t1());
784 } );
785
787 XO("Trim selected audio tracks from %.2f seconds to %.2f seconds")
788 .Format( selectedRegion.t0(), selectedRegion.t1() ),
789 XO("Trim Audio"));
790}
791
792void OnSplit(const CommandContext &context)
793{
794 auto &project = context.project;
796 auto [sel0, sel1] = FindSelection(context);
797 if (auto *pTrack = *tracks.Find(context.temporarySelection.pTrack)) {
798 if (auto pWaveTrack = dynamic_cast<WaveTrack*>(pTrack))
799 pWaveTrack->Split(sel0, sel1);
800 else
801 // Did nothing, don't push history
802 return;
803 }
804 else
805 for (auto wt : tracks.Selected<WaveTrack>())
806 wt->Split(sel0, sel1);
807
808 ProjectHistory::Get( project ).PushState(XO("Split"), XO("Split"));
809#if 0
810//ANSWER-ME: Do we need to keep this commented out OnSplit() code?
811// This whole section no longer used...
812 /*
813 * Previous (pre-multiclip) implementation of "Split" command
814 * This does work only when a range is selected!
815 *
816 TrackListIterator iter(tracks);
817
818 Track *n = iter.First();
819 Track *dest;
820
821 TrackList newTracks;
822
823 while (n) {
824 if (n->GetSelected()) {
825 double sel0 = selectedRegion.t0();
826 double sel1 = selectedRegion.t1();
827
828 dest = n->Copy(sel0, sel1);
829 dest->Init(*n);
830 dest->MoveTo(std::max(sel0, n->GetOffset()));
831
832 if (sel1 >= n->GetEndTime())
833 n->Clear(sel0, sel1);
834 else if (sel0 <= n->GetOffset()) {
835 n->Clear(sel0, sel1);
836 n->MoveTo(sel1);
837 } else
838 n->Silence(sel0, sel1);
839
840 newTracks.Add(dest);
841 }
842 n = iter.Next();
843 }
844
845 TrackListIterator nIter(&newTracks);
846 n = nIter.First();
847 while (n) {
848 tracks->Add(n);
849 n = nIter.Next();
850 }
851
852 PushState(XO("Split"), XO("Split"));
853 */
854#endif
855}
856
857void OnSplitNew(const CommandContext &context)
858{
859 auto &project = context.project;
861 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
862
863 // This iteration is unusual because we add to the list inside the loop
864 auto range = tracks.Selected();
865 auto last = *range.rbegin();
866 for (auto track : range) {
867 track->TypeSwitch(
868 [&](WaveTrack &wt) {
869 // Clips must be aligned to sample positions or the NEW clip will
870 // not fit in the gap where it came from
871 const double newt0 = wt.SnapToSample(selectedRegion.t0());
872 const double newt1 = wt.SnapToSample(selectedRegion.t1());
873 // Fix issue 2846 by calling copy with forClipboard = false.
874 // This avoids creating the blank placeholder clips
875 const auto dest = wt.Copy(newt0, newt1, false);
876 if (dest) {
877 // The copy function normally puts the clip at time 0
878 // This offset lines it up with the original track's timing
879 (*dest->begin())->MoveTo(newt0);
880 tracks.Append(std::move(*dest));
881 }
882 wt.SplitDelete(newt0, newt1);
883 }
884#if 0
885 ,
886 // LL: For now, just skip all non-wave tracks since the other do not
887 // yet support proper splitting.
888 [&](Track &n) {
889 dest = n.Cut(viewInfo.selectedRegion.t0(),
890 viewInfo.selectedRegion.t1());
891 if (dest) {
892 dest->MoveTo(std::max(0, n.GetOffset()));
893 tracks.Add(dest);
894 }
895 }
896#endif
897 );
898 if (track == last)
899 break;
900 }
901
903 .PushState(XO("Split to new track"), XO("Split New"));
904}
905
906void OnJoin(const CommandContext &context)
907{
908 auto &project = context.project;
910 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
911 const auto selectedTracks = tracks.Selected<WaveTrack>();
913 [&](const ProgressReporter& reportProgress) {
914 using namespace BasicUI;
916 selectedTracks.begin(), selectedTracks.end(),
917 [&](WaveTrack* wt, const ProgressReporter& childProgress) {
918 wt->Join(
919 selectedRegion.t0(), selectedRegion.t1(), childProgress);
920 },
921 reportProgress);
922 });
923
925 XO("Joined %.2f seconds at t=%.2f")
926 .Format(selectedRegion.duration(), selectedRegion.t0()),
927 XO("Join"));
928}
929
930void OnDisjoin(const CommandContext &context)
931{
932 auto &project = context.project;
934 auto &selectedRegion = ViewInfo::Get(project).selectedRegion;
935
936 for (auto wt : tracks.Selected<WaveTrack>())
937 wt->Disjoin(selectedRegion.t0(), selectedRegion.t1());
938
940 XO("Detached %.2f seconds at t=%.2f")
941 .Format(selectedRegion.duration(), selectedRegion.t0()),
942 XO("Detach"));
943}
944
945void OnPreferences(const CommandContext &context)
946{
947 auto &project = context.project;
948
949 GlobalPrefsDialog dialog(&GetProjectFrame(project) /* parent */, &project );
950
951 if (!dialog.ShowModal()) {
952 // Canceled
953 return;
954 }
955
956 // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with
957 // rebuilding the menus while the PrefsDialog is still in the modal
958 // state.
959 for (auto p : AllProjects{}) {
961// TODO: The comment below suggests this workaround is obsolete.
962#if defined(__WXGTK__)
963 // Workaround for:
964 //
965 // http://bugzilla.audacityteam.org/show_bug.cgi?id=458
966 //
967 // This workaround should be removed when Audacity updates to wxWidgets
968 // 3.x which has a fix.
969 auto &window = GetProjectFrame( *p );
970 wxRect r = window.GetRect();
971 window.SetSize(wxSize(1,1));
972 window.SetSize(r.GetSize());
973#endif
974 }
975}
976
977// Legacy functions, not used as of version 2.3.0
978
979#if 0
980void OnPasteOver(const CommandContext &context)
981{
982 auto &project = context.project;
983 auto &selectedRegion = project.GetViewInfo().selectedRegion;
984
985 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
986 {
987 selectedRegion.setT1(
988 selectedRegion.t0() +
989 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
990 // MJS: pointless, given what we do in OnPaste?
991 }
992 OnPaste(context);
993
994 return;
995}
996#endif
997
998// Menu definitions
999
1002 [](const AudacityProject &project){
1003 auto range = TrackList::Get(project).Any<const LabelTrack>()
1004 + [&](const LabelTrack *pTrack){
1005 return LabelTrackView::Get( *pTrack ).IsTextSelected(
1006 // unhappy const_cast because track focus might be set
1007 const_cast<AudacityProject&>(project)
1008 );
1009 };
1010 if ( !range.empty() )
1011 return true;
1012
1013 if (
1015 &&
1017 )
1018 return true;
1019
1020 return false;
1021 },
1023}; return flag; }
1024
1027 [](const AudacityProject &project)
1028 {
1030 return false;
1031
1032 const auto &viewInfo = ViewInfo::Get(project);
1033 if(viewInfo.selectedRegion.isPoint())
1034 return false;
1035
1036 const auto selectedTracks = TrackList::Get(project).Selected<const WaveTrack>();
1037 for(const auto track : selectedTracks)
1038 {
1039 const auto selectedClips =
1040 track->GetClipsIntersecting(viewInfo.selectedRegion.t0(), viewInfo.selectedRegion.t1());
1041 if(selectedClips.size() > 1)
1042 return true;
1043 }
1044 return false;
1045 },
1047}; return flag; }
1048
1049using namespace MenuRegistry;
1051{
1052 static const auto NotBusyTimeAndTracksFlags =
1054
1055 // The default shortcut key for Redo is different on different platforms.
1056 static constexpr auto redoKey =
1057#ifdef __WXMSW__
1058 wxT("Ctrl+Y")
1059#else
1060 wxT("Ctrl+Shift+Z")
1061#endif
1062 ;
1063
1064 // The default shortcut key for Preferences is different on different
1065 // platforms.
1066 static constexpr auto prefKey =
1067#ifdef __WXMAC__
1068 wxT("Ctrl+,")
1069#else
1070 wxT("Ctrl+P")
1071#endif
1072 ;
1073
1074 static auto menu = std::shared_ptr{
1075 Menu( wxT("Edit"), XXO("&Edit"),
1076 Section( "UndoRedo",
1077 Command( wxT("Undo"), XXO("&Undo"), OnUndo,
1078 AudioIONotBusyFlag() | UndoAvailableFlag(), wxT("Ctrl+Z") ),
1079
1080 Command( wxT("Redo"), XXO("&Redo"), OnRedo,
1081 AudioIONotBusyFlag() | RedoAvailableFlag(), redoKey ),
1082
1083 MenuCreator::Special( wxT("UndoItemsUpdateStep"),
1084 [](AudacityProject &project, wxMenu&) {
1085 // Change names in the CommandManager as a side-effect
1087 })
1088 ),
1089
1090 Section( "Basic",
1091 // Basic Edit commands
1092 /* i18n-hint: (verb)*/
1093 Command( wxT("Cut"), XXO("Cu&t"), OnCut,
1095 wxT("Ctrl+X") ),
1096 Command( wxT("Delete"), XXO("&Delete"), OnDelete,
1098 wxT("Ctrl+K") ),
1099 /* i18n-hint: (verb)*/
1100 Command( wxT("Copy"), XXO("&Copy"), OnCopy,
1101 AudioIONotBusyFlag() | CutCopyAvailableFlag(), wxT("Ctrl+C") ),
1102 /* i18n-hint: (verb)*/
1103 Command( wxT("Paste"), XXO("&Paste"), OnPaste,
1104 AudioIONotBusyFlag(), wxT("Ctrl+V") ),
1105 /* i18n-hint: (verb)*/
1106 Command( wxT("Duplicate"), XXO("Duplic&ate"), OnDuplicate,
1107 NotBusyTimeAndTracksFlags, wxT("Ctrl+D") ),
1108
1109 Section( "",
1110 Menu( wxT("RemoveSpecial"), XXO("R&emove Special"),
1111 Section( "",
1112 /* i18n-hint: (verb) Do a special kind of cut*/
1113 Command( wxT("SplitCut"), XXO("Spl&it Cut"), OnSplitCut,
1114 NotBusyTimeAndTracksFlags,
1115 Options{ wxT("Ctrl+Alt+X") } ),
1116 /* i18n-hint: (verb) Do a special kind of DELETE*/
1117 Command( wxT("SplitDelete"), XXO("Split D&elete"), OnSplitDelete,
1118 NotBusyTimeAndTracksFlags,
1119 Options{ wxT("Ctrl+Alt+K") } )
1120 ),
1121
1122 Section( "",
1123 /* i18n-hint: (verb)*/
1124 Command( wxT("Silence"), XXO("Silence Audi&o"), OnSilence,
1126 wxT("Ctrl+L") ),
1127 /* i18n-hint: (verb)*/
1128 Command( wxT("Trim"), XXO("Tri&m Audio"), OnTrim,
1130 Options{ wxT("Ctrl+T") } )
1131 )
1132 )
1133 )
1134 ),
1135
1136
1137 Section( "Other",
1139
1140 Menu( wxT("Clip"), XXO("Audi&o Clips"),
1141 Section( "",
1142 /* i18n-hint: (verb) It's an item on a menu. */
1143 Command( wxT("Split"), XXO("Sp&lit"), OnSplit,
1145 Options{ wxT("Ctrl+I") } ),
1146 Command( wxT("SplitNew"), XXO("Split Ne&w"), OnSplitNew,
1148 Options{ wxT("Ctrl+Alt+I") } )
1149 ),
1150
1151 Section( "",
1152 /* i18n-hint: (verb)*/
1153 Command( wxT("Join"), XXO("&Join"), OnJoin,
1154 JoinClipsAvailableFlag(), wxT("Ctrl+J") ),
1155 Command( wxT("Disjoin"), XXO("Detac&h at Silences"), OnDisjoin,
1156 NotBusyTimeAndTracksFlags, wxT("Ctrl+Alt+J") )
1157 )
1158 )
1159
1160 ),
1161
1162 // Note that on Mac, the Preferences menu item is specially handled in
1163 // CommandManager (assigned a special wxWidgets id) so that it does
1164 // not appear in the Edit menu but instead under Audacity, consistent with
1165 // MacOS conventions.
1166 Section( "Preferences",
1167 Command( wxT("Preferences"), XXO("Pre&ferences"), OnPreferences,
1168 AudioIONotBusyFlag(), prefKey )
1169 )
1170
1171 ) };
1172 return menu;
1173}
1174
1176
1178{
1179 static const auto flags =
1181 static auto menu = std::shared_ptr{
1182 Menu( wxT("Edit"), XXO("&Edit"),
1183 Command( wxT("DeleteKey"), XXO("&Delete Key"), OnDelete,
1184 (flags | NoAutoSelect()),
1185 wxT("Backspace") ),
1186 Command( wxT("DeleteKey2"), XXO("Delete Key&2"), OnDelete,
1187 (flags | NoAutoSelect()),
1188 wxT("Delete") )
1189 ) };
1190 return menu;
1191}
1192
1197 (flagsRqd & NoAutoSelect()).none() )
1199};
1200
1202 []{ return TracksExistFlag(); },
1203 []{ return EditableTracksSelectedFlag(); },
1205 selectAll
1206}};
1207
1208// Including time tracks.
1210 []{ return TracksExistFlag(); },
1211 []{ return AnyTracksSelectedFlag(); },
1213 selectAll
1214}};
1215
1217 []{ return WaveTracksExistFlag(); },
1220 selectAll
1221}};
1222
1223// Also enable select for the noise reduction case.
1225 []{ return WaveTracksExistFlag(); },
1228 selectAll
1229}};
1230
1232 wxT("Optional/Extra/Part1")
1233};
1234
1235}
wxT("CloseDown"))
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()
bool AudioIOBusyPred(const AudacityProject &project)
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & AnyTracksSelectedFlag()
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:333
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
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:52
const auto tracks
const auto project
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
std::function< void(double)> ProgressReporter
Definition: Track.h:53
ChoiceSetting TracksBehaviorsAudioTrackPastePolicy
An AudacityException with no visible message.
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:388
static Clipboard & Get()
Definition: Clipboard.cpp:28
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
TemporarySelection temporarySelection
AudacityProject & project
static CommandManager & Get(AudacityProject &project)
Abstract base class used in importing a file.
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:87
static LabelTrackView & Get(LabelTrack &)
bool IsTextSelected(AudacityProject &project) const
int GetTextEditIndex(AudacityProject &project) const
static constexpr auto Special
Definition: MenuCreator.h:36
void RebuildMenuBar()
static MenuCreator & Get(AudacityProject &project)
Definition: MenuCreator.cpp:91
A Track that is used for Midi notes. (Somewhat old code).
Definition: NoteTrack.h:86
TrackListHolder Cut(double t0, double t1) override
Create tracks and modify this track.
Definition: NoteTrack.cpp:327
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
Definition: NoteTrack.cpp:358
void Clear(double t0, double t1) override
Definition: NoteTrack.cpp:405
double duration() const
Definition: ViewInfo.h:41
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 ProjectTimeSignature & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
Definition: Registry.h:388
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
Definition: SyncLock.cpp:112
static TrackIterRange< Track > Group(Track *pTrack)
Definition: SyncLock.cpp:161
bool IsSyncLocked() const
Definition: SyncLock.cpp:43
static SyncLockState & Get(AudacityProject &project)
Definition: SyncLock.cpp:26
Track * Get()
Definition: TrackFocus.cpp:156
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:122
virtual void SetSelected(bool s)
Definition: Track.cpp:75
virtual Holder PasteInto(AudacityProject &project, TrackList &list) const =0
bool SameKindAs(const Track &track) const
Definition: Track.h:428
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
Definition: Track.cpp:1213
R TypeSwitch(const Functions &...functions)
Definition: Track.h:436
const std::optional< double > & GetProjectTempo() const
Definition: Track.cpp:1369
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:993
static TrackListHolder Create(AudacityProject *pOwner)
Definition: Track.cpp:365
size_t NChannels() const
Definition: Track.cpp:960
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1097
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1114
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:233
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:215
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
void ShowTrack(const Track &track)
Definition: Viewport.cpp:454
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32
static WaveChannelView & Get(WaveChannel &channel)
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:4516
A Track that contains audio waveform data.
Definition: WaveTrack.h:227
void SplitDelete(double t0, double t1)
Definition: WaveTrack.cpp:1878
void Silence(double t0, double t1, ProgressReporter reportProgress) override
Definition: WaveTrack.cpp:2451
WaveClipConstHolders GetClipsIntersecting(double t0, double t1) const
Definition: WaveTrack.cpp:3742
void Trim(double t0, double t1)
Definition: WaveTrack.cpp:1330
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
Definition: WaveTrack.cpp:1408
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
Definition: WaveTrack.cpp:1541
TrackListHolder SplitCut(double t0, double t1)
Definition: WaveTrack.cpp:1315
double SnapToSample(double t) const
bool ReadBool(const wxString &key, bool defaultValue) const
virtual bool Read(const wxString &key, bool *value) const =0
std::function< void(double)> ProgressReporter
Definition: BasicUI.h:25
void SplitProgress(ItType first, ItType last, FnType action, ProgressReporter parent)
Helper for the update of a task's progress bar when this task is made of a range's subtasks.
Definition: BasicUI.h:329
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:292
constexpr auto Section
Definition: MenuRegistry.h:436
constexpr auto Command
Definition: MenuRegistry.h:456
constexpr auto Menu
Items will appear in a main toolbar menu or in a sub-menu.
Definition: MenuRegistry.h:445
MENUS_API void Visit(Visitor< Traits > &visitor, AudacityProject &project)
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
Definition: Registry.h:175
void DoSelectAllAudio(AudacityProject &project)
WAVE_TRACK_API void WithClipRenderingProgress(std::function< void(const ProgressReporter &)> action, TranslatableString title=defaultStretchRenderingTitle, TranslatableString message=XO("Rendering Clip"))
std::shared_ptr< const TrackList > FindSourceTracks(const CommandContext &context)
Definition: EditMenus.cpp:417
Correspondence FindCorrespondence(TrackList &dstTracks, const TrackList &srcTracks)
Definition: EditMenus.cpp:490
wxULongLong EstimateCopyBytesCount(const TrackList &src, const TrackList &dst)
Definition: EditMenus.cpp:87
BlockArray::size_type EstimateCopiedBlocks(const TrackList &src, const TrackList &dst)
Definition: EditMenus.cpp:98
void OnDisjoin(const CommandContext &context)
Definition: EditMenus.cpp:930
void DoPasteNothingSelected(AudacityProject &project, const TrackList &src, double t0, double t1)
Definition: EditMenus.cpp:124
bool DoPasteText(AudacityProject &project)
Definition: EditMenus.cpp:43
void OnRedo(const CommandContext &context)
Definition: EditMenus.cpp:205
void OnJoin(const CommandContext &context)
Definition: EditMenus.cpp:906
RegisteredMenuItemEnabler selectWaveTracks
Definition: EditMenus.cpp:1216
std::shared_ptr< TrackList > DuplicateDiscardTrimmed(const TrackList &src)
Definition: EditMenus.cpp:106
bool FitsInto(const Track &src, const Track &dst)
Whether the source track may be pasted into the destination track.
Definition: EditMenus.cpp:477
RegisteredMenuItemEnabler selectTracks
Definition: EditMenus.cpp:1201
void OnDelete(const CommandContext &context)
Definition: EditMenus.cpp:326
auto NotificationScope(const CommandContext &context, const TrackList &srcTracks)
Definition: EditMenus.cpp:450
void OnPaste(const CommandContext &context)
Definition: EditMenus.cpp:520
const ReservedCommandFlag & CutCopyAvailableFlag()
Definition: EditMenus.cpp:1001
void OnSplit(const CommandContext &context)
Definition: EditMenus.cpp:792
std::pair< double, double > FindSelection(const CommandContext &context)
Definition: EditMenus.cpp:395
void OnSilence(const CommandContext &context)
Definition: EditMenus.cpp:748
RegisteredMenuItemEnabler selectWaveTracks2
Definition: EditMenus.cpp:1224
const ReservedCommandFlag & JoinClipsAvailableFlag()
Definition: EditMenus.cpp:1026
void OnTrim(const CommandContext &context)
Definition: EditMenus.cpp:772
void OnSplitDelete(const CommandContext &context)
Definition: EditMenus.cpp:726
std::vector< std::pair< Track *, const Track * > > Correspondence
Definition: EditMenus.cpp:488
void OnCopy(const CommandContext &context)
Definition: EditMenus.cpp:351
void OnUndo(const CommandContext &context)
Definition: EditMenus.cpp:176
void OnSplitCut(const CommandContext &context)
Definition: EditMenus.cpp:692
void OnPreferences(const CommandContext &context)
Definition: EditMenus.cpp:945
void OnDuplicate(const CommandContext &context)
Definition: EditMenus.cpp:664
RegisteredMenuItemEnabler selectAnyTracks
Definition: EditMenus.cpp:1209
bool HasHiddenData(const TrackList &trackList)
Definition: EditMenus.cpp:167
void OnSplitNew(const CommandContext &context)
Definition: EditMenus.cpp:857
void OnCut(const CommandContext &context)
Definition: EditMenus.cpp:233
CommandFlagOptions && DisableDefaultMessage() &&
Definition: CommandFlag.h:53
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.
Definition: UndoManager.h:117
UndoState state
Definition: UndoManager.h:128