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