Audacity 3.2.0
LabelMenus.cpp
Go to the documentation of this file.
1#include "../AudioIO.h"
2#include "../Clipboard.h"
3#include "../CommonCommandFlags.h"
4#include "../LabelTrack.h"
5#include "../Menus.h"
6#include "Prefs.h"
7#include "Project.h"
8#include "../ProjectAudioIO.h"
9#include "ProjectHistory.h"
10#include "../ProjectSettings.h"
11#include "../ProjectWindow.h"
12#include "../SelectUtilities.h"
13#include "../SyncLock.h"
14#include "../TrackPanelAx.h"
15#include "../TrackPanel.h"
16#include "ViewInfo.h"
17#include "../WaveTrack.h"
18#include "../commands/CommandContext.h"
19#include "../commands/CommandManager.h"
20#include "../tracks/labeltrack/ui/LabelTrackView.h"
21
24
25// private helper classes and functions
26namespace {
27
30 [](const AudacityProject &project){
31 // At least one label track selected, having at least one label
32 // completely within the time selection.
33 const auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
34 const auto &test = [&]( const LabelTrack *pTrack ){
35 const auto &labels = pTrack->GetLabels();
36 return std::any_of( labels.begin(), labels.end(),
37 [&](const LabelStruct &label){
38 return
39 label.getT0() >= selectedRegion.t0()
40 &&
41 label.getT1() <= selectedRegion.t1()
42 ;
43 }
44 );
45 };
46 auto range = TrackList::Get( project ).Selected<const LabelTrack>()
47 + test;
48 return !range.empty();
49 }
50}; return flag; }
51
52//Adds label and returns index of label in labeltrack.
54 AudacityProject &project, const SelectedRegion &region,
55 bool preserveFocus = false)
56{
57 auto &tracks = TrackList::Get( project );
58 auto &trackFocus = TrackFocus::Get( project );
59 auto &trackPanel = TrackPanel::Get( project );
60
61 wxString title; // of label
62
63 bool useDialog;
64 gPrefs->Read(wxT("/GUI/DialogForNameNewLabel"), &useDialog, false);
65 if (useDialog) {
67 project, region, wxEmptyString, title) == wxID_CANCEL)
68 return -1; // index
69 }
70
71 // If the focused track is a label track, use that
72 const auto pFocusedTrack = trackFocus.Get();
73
74 // Look for a label track at or after the focused track
75 auto iter = pFocusedTrack
76 ? tracks.Find(pFocusedTrack)
77 : tracks.Any().begin();
78 auto lt = * iter.Filter< LabelTrack >();
79
80 // If none found, start a NEW label track and use it
81 if (!lt)
82 lt = LabelTrack::Create(tracks);
83
84// LLL: Commented as it seemed a little forceful to remove users
85// selection when adding the label. This does not happen if
86// you select several tracks and the last one of those is a
87// label track...typing a label will not clear the selections.
88//
89// SelectNone();
90 lt->SetSelected(true);
91
92 int index;
93 if (useDialog) {
94 index = lt->AddLabel(region, title);
95 }
96 else {
97 int focusTrackNumber = -1;
98 if (pFocusedTrack && preserveFocus) {
99 // Must remember the track to re-focus after finishing a label edit.
100 // do NOT identify it by a pointer, which might dangle! Identify
101 // by position.
102 focusTrackNumber = pFocusedTrack->GetIndex();
103 }
104 index =
105 LabelTrackView::Get( *lt ).AddLabel(region, title, focusTrackNumber);
106 }
107
108 ProjectHistory::Get( project )
109 .PushState(XO("Added label"), XO("Label"));
110
111 if (!useDialog) {
112 TrackFocus::Get(project).Set(lt);
113 lt->EnsureVisible();
114 }
115 trackPanel.SetFocus();
116
117 return index;
118}
119
120//get regions selected by selected labels
121//removes unnecessary regions, overlapping regions are merged
123 const TrackList &tracks, const SelectedRegion &selectedRegion,
124 Regions &regions )
125{
126 //determine labeled regions
127 for (auto lt : tracks.Selected< const LabelTrack >()) {
128 for (int i = 0; i < lt->GetNumLabels(); i++)
129 {
130 const LabelStruct *ls = lt->GetLabel(i);
131 if (ls->selectedRegion.t0() >= selectedRegion.t0() &&
132 ls->selectedRegion.t1() <= selectedRegion.t1())
133 regions.push_back(Region(ls->getT0(), ls->getT1()));
134 }
135 }
136
137 //anything to do ?
138 if( regions.size() == 0 )
139 return;
140
141 //sort and remove unnecessary regions
142 std::sort(regions.begin(), regions.end());
143 unsigned int selected = 1;
144 while( selected < regions.size() )
145 {
146 const Region &cur = regions.at( selected );
147 Region &last = regions.at( selected - 1 );
148 if( cur.start < last.end )
149 {
150 if( cur.end > last.end )
151 last.end = cur.end;
152 regions.erase( regions.begin() + selected );
153 }
154 else
155 ++selected;
156 }
157}
158
159using EditFunction = std::function<void(Track *, double, double)>;
160
161//Executes the edit function on all selected wave tracks with
162//regions specified by selected labels
163//If No tracks selected, function is applied on all tracks
164//If the function replaces the selection with audio of a different length,
165// bSyncLockedTracks should be set true to perform the same action on sync-lock
166// selected tracks.
168 TrackList &tracks, const SelectedRegion &selectedRegion,
169 EditFunction action)
170{
171 Regions regions;
172
173 GetRegionsByLabel( tracks, selectedRegion, regions );
174 if( regions.size() == 0 )
175 return;
176
177 const bool notLocked = (!ProjectSettings::Get(project).IsSyncLocked() &&
178 (tracks.Selected<PlayableTrack>()).empty());
179
180 //Apply action on tracks starting from
181 //labeled regions in the end. This is to correctly perform
182 //actions like 'Delete' which collapse the track area.
183 for (auto t : tracks.Any())
184 {
185 const bool playable = dynamic_cast<const PlayableTrack *>(t) != nullptr;
186
187 if (SyncLock::IsSyncLockSelected(t) || notLocked && playable)
188 {
189 for (int i = (int)regions.size() - 1; i >= 0; i--)
190 {
191 const Region &region = regions.at(i);
192 action(t, region.start, region.end);
193 }
194 }
195 }
196}
197
198using EditDestFunction = std::function<Track::Holder (Track *, double, double)>;
199
200//Executes the edit function on all selected wave tracks with
201//regions specified by selected labels
202//If No tracks selected, function is applied on all tracks
203//Functions copy the edited regions to clipboard, possibly in multiple tracks
204//This probably should not be called if *action() changes the timeline, because
205// the copy needs to happen by track, and the timeline change by group.
207 TrackList &tracks, const SelectedRegion &selectedRegion,
208 EditDestFunction action )
209{
210 Regions regions;
211
212 GetRegionsByLabel( tracks, selectedRegion, regions );
213 if( regions.size() == 0 )
214 return;
215
216 const bool notLocked = (!ProjectSettings::Get(project).IsSyncLocked() &&
217 (tracks.Selected<PlayableTrack>()).empty());
218
219 auto &clipboard = Clipboard::Get();
220 clipboard.Clear();
221
222 auto pNewClipboard = TrackList::Create( nullptr );
223 auto &newClipboard = *pNewClipboard;
224
225 //Apply action on wavetracks starting from
226 //labeled regions in the end. This is to correctly perform
227 //actions like 'Cut' which collapse the track area.
228
229 for( auto t : tracks.Any())
230 {
231 const bool playable = dynamic_cast<const PlayableTrack *>(t) != nullptr;
232
233 if (SyncLock::IsSyncLockSelected(t) || notLocked && playable)
234 {
235 // This track accumulates the needed clips, right to left:
236 Track::Holder merged;
237 for( int i = (int)regions.size() - 1; i >= 0; i-- )
238 {
239 const Region &region = regions.at(i);
240 auto dest = action(t, region.start, region.end );
241 if( dest )
242 {
243 Track::FinishCopy( t, dest.get() );
244 if( !merged )
245 merged = dest;
246 else
247 {
248 // Paste to the beginning; unless this is the first region,
249 // offset the track to account for time between the regions
250 if (i < (int)regions.size() - 1)
251 merged->Offset(
252 regions.at(i + 1).start - region.end);
253
254 // dest may have a placeholder clip at the end that is
255 // removed when pasting, which is okay because we proceed
256 // right to left. Any placeholder already in merged is kept.
257 // Only the rightmost placeholder is important in the final
258 // result.
259 merged->Paste( 0.0 , dest.get() );
260 }
261 }
262 else
263 // nothing copied but there is a 'region', so the 'region' must
264 // be a 'point label' so offset
265 if (i < (int)regions.size() - 1)
266 if (merged)
267 merged->Offset(
268 regions.at(i + 1).start - region.end);
269 }
270 if( merged )
271 newClipboard.Add( merged );
272 }
273 }
274
275 // Survived possibility of exceptions. Commit changes to the clipboard now.
276 clipboard.Assign( std::move( newClipboard ),
277 regions.front().start, regions.back().end, project.shared_from_this() );
278}
279
280}
281
284
285// exported helper functions
286// none
287
288// Menu handler functions
289
291
292void OnEditLabels(const CommandContext &context)
293{
294 auto &project = context.project;
296}
297
298void OnAddLabel(const CommandContext &context)
299{
300 auto &project = context.project;
301 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
302
303 DoAddLabel(project, selectedRegion);
304}
305
307{
308 auto &project = context.project;
309 auto token = ProjectAudioIO::Get( project ).GetAudioIOToken();
310
311 auto gAudioIO = AudioIO::Get();
312 if (token > 0 &&
313 gAudioIO->IsStreamActive(token)) {
314 double indicator = gAudioIO->GetStreamTime();
315 DoAddLabel(project, SelectedRegion(indicator, indicator), true);
316 }
317}
318
319// Creates a NEW label in each selected label track with text from the system
320// clipboard
321void OnPasteNewLabel(const CommandContext &context)
322{
323 auto &project = context.project;
324 auto &tracks = TrackList::Get( project );
325 auto &trackPanel = TrackPanel::Get( project );
326 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
327
328 bool bPastedSomething = false;
329
330 {
331 auto trackRange = tracks.Selected< const LabelTrack >();
332 if (trackRange.empty())
333 {
334 // If there are no selected label tracks, try to choose the first label
335 // track after some other selected track
336 Track *t = *tracks.Selected().begin()
337 .Filter( &Track::Any )
338 .Filter<LabelTrack>();
339
340 // If no match found, add one
341 if (!t)
342 t = LabelTrack::Create(tracks);
343
344 // Select this track so the loop picks it up
345 t->SetSelected(true);
346 }
347 }
348
349 LabelTrack *plt = NULL; // the previous track
350 for ( auto lt : tracks.Selected< LabelTrack >() )
351 {
352 // Unselect the last label, so we'll have just one active label when
353 // we're done
354 if (plt)
356
357 // Add a NEW label, paste into it
358 // Paul L: copy whatever defines the selected region, not just times
359 auto &view = LabelTrackView::Get( *lt );
360 view.AddLabel(selectedRegion);
361 if (view.PasteSelectedText( context.project, selectedRegion.t0(),
362 selectedRegion.t1() ))
363 bPastedSomething = true;
364
365 // Set previous track
366 plt = lt;
367 }
368
369 // plt should point to the last label track pasted to -- ensure it's visible
370 // and set focus
371 if (plt) {
372 TrackFocus::Get(project).Set(plt);
373 plt->EnsureVisible();
374 trackPanel.SetFocus();
375 }
376
377 if (bPastedSomething) {
379 XO("Pasted from the clipboard"), XO("Paste Text to New Label"));
380 }
381}
382
383void OnToggleTypeToCreateLabel(const CommandContext &WXUNUSED(context) )
384{
385 bool typeToCreateLabel;
386 gPrefs->Read(wxT("/GUI/TypeToCreateLabel"), &typeToCreateLabel, false);
387 gPrefs->Write(wxT("/GUI/TypeToCreateLabel"), !typeToCreateLabel);
388 gPrefs->Flush();
390}
391
392void OnCutLabels(const CommandContext &context)
393{
394 auto &project = context.project;
395 auto &tracks = TrackList::Get( project );
396 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
397
398 if( selectedRegion.isPoint() )
399 return;
400
401 // Because of grouping the copy may need to operate on different tracks than
402 // the clear, so we do these actions separately.
403 auto copyfunc = [&](Track *track, double t0, double t1)
404 {
405 Track::Holder dest = nullptr;
406 track->TypeSwitch(
407 [&](WaveTrack *t)
408 {
409 dest = t->CopyNonconst(t0, t1);
410 }
411 );
412 return dest;
413 };
414 EditClipboardByLabel( project, tracks, selectedRegion, copyfunc );
415
416 bool enableCutlines = gPrefs->ReadBool(wxT( "/GUI/EnableCutLines"), false);
417 auto editfunc = [&](Track *track, double t0, double t1)
418 {
419 track->TypeSwitch(
420 [&](WaveTrack *t)
421 {
422 if (enableCutlines)
423 {
424 t->ClearAndAddCutLine(t0, t1);
425 }
426 else
427 {
428 t->Clear(t0, t1);
429 }
430 },
431 [&](Track *t)
432 {
433 t->Clear(t0, t1);
434 }
435 );
436 };
437 EditByLabel(project, tracks, selectedRegion, editfunc);
438
439 selectedRegion.collapseToT0();
440
442 /* i18n-hint: (verb) past tense. Audacity has just cut the labeled audio
443 regions.*/
444 XO( "Cut labeled audio regions to clipboard" ),
445 /* i18n-hint: (verb)*/
446 XO( "Cut Labeled Audio" ) );
447}
448
449void OnDeleteLabels(const CommandContext &context)
450{
451 auto &project = context.project;
452 auto &tracks = TrackList::Get( project );
453 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
454
455 if( selectedRegion.isPoint() )
456 return;
457
458 auto editfunc = [&](Track *track, double t0, double t1)
459 {
460 track->Clear(t0, t1);
461 };
462 EditByLabel(project, tracks, selectedRegion, editfunc);
463
464 selectedRegion.collapseToT0();
465
467 /* i18n-hint: (verb) Audacity has just deleted the labeled audio regions*/
468 XO( "Deleted labeled audio regions" ),
469 /* i18n-hint: (verb)*/
470 XO( "Delete Labeled Audio" ) );
471}
472
474{
475 auto &project = context.project;
476 auto &tracks = TrackList::Get( project );
477 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
478
479 if( selectedRegion.isPoint() )
480 return;
481
482 auto copyfunc = [&](Track *track, double t0, double t1)
483 {
484 Track::Holder dest = nullptr;
485 track->TypeSwitch(
486 [&](WaveTrack *t)
487 {
488 dest = t->SplitCut(t0, t1);
489 },
490 [&](Track *t)
491 {
492 dest = t->Copy(t0, t1);
493 t->Silence(t0, t1);
494 }
495 );
496 return dest;
497 };
498 EditClipboardByLabel( project, tracks, selectedRegion, copyfunc );
499
501 /* i18n-hint: (verb) Audacity has just split cut the labeled audio
502 regions*/
503 XO( "Split Cut labeled audio regions to clipboard" ),
504 /* i18n-hint: (verb) Do a special kind of cut on the labels*/
505 XO( "Split Cut Labeled Audio" ) );
506}
507
509{
510 auto &project = context.project;
511 auto &tracks = TrackList::Get( project );
512 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
513
514 if( selectedRegion.isPoint() )
515 return;
516
517 auto editfunc = [&](Track *track, double t0, double t1)
518 {
519 track->TypeSwitch(
520 [&](WaveTrack *t)
521 {
522 t->SplitDelete(t0, t1);
523 },
524 [&](Track *t)
525 {
526 t->Silence(t0, t1);
527 }
528 );
529 };
530 EditByLabel(project, tracks, selectedRegion, editfunc);
531
533 /* i18n-hint: (verb) Audacity has just done a special kind of DELETE on
534 the labeled audio regions */
535 XO( "Split Deleted labeled audio regions" ),
536 /* i18n-hint: (verb) Do a special kind of DELETE on labeled audio
537 regions */
538 XO( "Split Delete Labeled Audio" ) );
539}
540
541void OnSilenceLabels(const CommandContext &context)
542{
543 auto &project = context.project;
544 auto &tracks = TrackList::Get( project );
545 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
546
547 if( selectedRegion.isPoint() )
548 return;
549
550 auto editfunc = [&](Track *track, double t0, double t1)
551 {
552 track->TypeSwitch(
553 [&](WaveTrack *t)
554 {
555 t->Silence(t0, t1);
556 }
557 );
558 };
559 EditByLabel(project, tracks, selectedRegion, editfunc);
560
562 /* i18n-hint: (verb)*/
563 XO( "Silenced labeled audio regions" ),
564 /* i18n-hint: (verb)*/
565 XO( "Silence Labeled Audio" ) );
566}
567
568void OnCopyLabels(const CommandContext &context)
569{
570 auto &project = context.project;
571 auto &tracks = TrackList::Get( project );
572 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
573
574 if( selectedRegion.isPoint() )
575 return;
576
577 auto copyfunc = [&](Track *track, double t0, double t1)
578 {
579 Track::Holder dest = nullptr;
580 track->TypeSwitch(
581 [&](WaveTrack *t)
582 {
583 dest = t->CopyNonconst(t0, t1);
584 });
585 return dest;
586 };
587 EditClipboardByLabel( project, tracks, selectedRegion, copyfunc );
588
589 ProjectHistory::Get( project ).PushState( XO( "Copied labeled audio regions to clipboard" ),
590 /* i18n-hint: (verb)*/
591 XO( "Copy Labeled Audio" ) );
592}
593
594void OnSplitLabels(const CommandContext &context)
595{
596 auto &project = context.project;
597 auto &tracks = TrackList::Get( project );
598 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
599
600 if( selectedRegion.isPoint() )
601 return;
602
603 auto editfunc = [&](Track *track, double t0, double t1)
604 {
605 track->TypeSwitch(
606 [&](WaveTrack *t)
607 {
608 t->Split(t0, t1);
609 }
610 );
611 };
612 EditByLabel(project, tracks, selectedRegion, editfunc);
613
615 /* i18n-hint: (verb) past tense. Audacity has just split the labeled
616 audio (a point or a region)*/
617 XO( "Split labeled audio (points or regions)" ),
618 /* i18n-hint: (verb)*/
619 XO( "Split Labeled Audio" ) );
620}
621
622void OnJoinLabels(const CommandContext &context)
623{
624 auto &project = context.project;
625 auto &tracks = TrackList::Get( project );
626 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
627
628 if( selectedRegion.isPoint() )
629 return;
630
631 auto editfunc = [&](Track *track, double t0, double t1)
632 {
633 track->TypeSwitch(
634 [&](WaveTrack *t)
635 {
636 t->Join(t0, t1);
637 }
638 );
639 };
640 EditByLabel(project, tracks, selectedRegion, editfunc);
641
643 /* i18n-hint: (verb) Audacity has just joined the labeled audio (points or
644 regions) */
645 XO( "Joined labeled audio (points or regions)" ),
646 /* i18n-hint: (verb) */
647 XO( "Join Labeled Audio" ) );
648}
649
650void OnDisjoinLabels(const CommandContext &context)
651{
652 auto &project = context.project;
653 auto &tracks = TrackList::Get( project );
654 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
655
656 if( selectedRegion.isPoint() )
657 return;
658
659 auto editfunc = [&](Track *track, double t0, double t1)
660 {
661 track->TypeSwitch(
662 [&](WaveTrack *t)
663 {
664 wxBusyCursor busy;
665 t->Disjoin(t0, t1);
666 }
667 );
668 };
669 EditByLabel(project, tracks, selectedRegion, editfunc);
670
672 /* i18n-hint: (verb) Audacity has just detached the labeled audio regions.
673 This message appears in history and tells you about something
674 Audacity has done.*/
675 XO( "Detached labeled audio regions" ),
676 /* i18n-hint: (verb)*/
677 XO( "Detach Labeled Audio" ) );
678}
679
680void OnNewLabelTrack(const CommandContext &context)
681{
682 auto &project = context.project;
683 auto &tracks = TrackList::Get( project );
684
685 auto track = LabelTrack::Create(tracks);
686
688
689 track->SetSelected(true);
690
691 ProjectHistory::Get( project )
692 .PushState(XO("Created new label track"), XO("New Track"));
693
694 TrackFocus::Get(project).Set(track);
695 track->EnsureVisible();
696}
697
698}; // struct Handler
699
700} // namespace
701
703 // Handler is not stateful. Doesn't need a factory registered with
704 // AudacityProject.
705 static LabelEditActions::Handler instance;
706 return instance;
707};
708
709// Menu definitions
710
711#define FN(X) (& LabelEditActions::Handler :: X)
712
713namespace {
714using namespace MenuTable;
716{
717 using namespace MenuTable;
719
720 static const auto NotBusyLabelsAndWaveFlags =
723
724 // Returns TWO menus.
725
726 static BaseItemSharedPtr menus{
728 Items( wxT("LabelEditMenus"),
729
730 Menu( wxT("Labels"), XXO("&Labels"),
731 Section( "",
732 Command( wxT("EditLabels"), XXO("&Edit Labels..."), FN(OnEditLabels),
734 ),
735
736 Section( "",
737 Command( wxT("AddLabel"), XXO("Add Label at &Selection"),
738 FN(OnAddLabel), AlwaysEnabledFlag, wxT("Ctrl+B") ),
739 Command( wxT("AddLabelPlaying"),
740 XXO("Add Label at &Playback Position"),
741 FN(OnAddLabelPlaying), AudioIOBusyFlag(),
742 #ifdef __WXMAC__
743 wxT("Ctrl+.")
744 #else
745 wxT("Ctrl+M")
746 #endif
747 ),
748 Command( wxT("PasteNewLabel"), XXO("Paste Te&xt to New Label"),
749 FN(OnPasteNewLabel),
750 AudioIONotBusyFlag(), wxT("Ctrl+Alt+V") )
751 ),
752
753 Section( "",
754 Command( wxT("TypeToCreateLabel"),
755 XXO("&Type to Create a Label (on/off)"),
756 FN(OnToggleTypeToCreateLabel), AlwaysEnabledFlag,
757 Options{}.CheckTest(wxT("/GUI/TypeToCreateLabel"), false) )
758 )
759 ), // first menu
760
762
763 Menu( wxT("Labeled"), XXO("La&beled Audio"),
764 Section( "",
765 /* i18n-hint: (verb)*/
766 Command( wxT("CutLabels"), XXO("&Cut"), FN(OnCutLabels),
769 Options{ wxT("Alt+X"), XO("Label Cut") } ),
770 Command( wxT("DeleteLabels"), XXO("&Delete"), FN(OnDeleteLabels),
773 Options{ wxT("Alt+K"), XO("Label Delete") } )
774 ),
775
776 Section( "",
777 /* i18n-hint: (verb) A special way to cut out a piece of audio*/
778 Command( wxT("SplitCutLabels"), XXO("&Split Cut"),
779 FN(OnSplitCutLabels), NotBusyLabelsAndWaveFlags,
780 Options{ wxT("Alt+Shift+X"), XO("Label Split Cut") } ),
781 Command( wxT("SplitDeleteLabels"), XXO("Sp&lit Delete"),
782 FN(OnSplitDeleteLabels), NotBusyLabelsAndWaveFlags,
783 Options{ wxT("Alt+Shift+K"), XO("Label Split Delete") } )
784 ),
785
786 Section( "",
787 Command( wxT("SilenceLabels"), XXO("Silence &Audio"),
788 FN(OnSilenceLabels), NotBusyLabelsAndWaveFlags,
789 Options{ wxT("Alt+L"), XO("Label Silence") } ),
790 /* i18n-hint: (verb)*/
791 Command( wxT("CopyLabels"), XXO("Co&py"), FN(OnCopyLabels),
792 NotBusyLabelsAndWaveFlags,
793 Options{ wxT("Alt+Shift+C"), XO("Label Copy") } )
794 ),
795
796 Section( "",
797 /* i18n-hint: (verb)*/
798 Command( wxT("SplitLabels"), XXO("Spli&t"), FN(OnSplitLabels),
800 Options{ wxT("Alt+I"), XO("Label Split") } ),
801 /* i18n-hint: (verb)*/
802 Command( wxT("JoinLabels"), XXO("&Join"), FN(OnJoinLabels),
803 NotBusyLabelsAndWaveFlags,
804 Options{ wxT("Alt+J"), XO("Label Join") } ),
805 Command( wxT("DisjoinLabels"), XXO("Detac&h at Silences"),
806 FN(OnDisjoinLabels), NotBusyLabelsAndWaveFlags,
807 wxT("Alt+Shift+J") )
808 )
809 ) // second menu
810
811 ) ) }; // two menus
812 return menus;
813}
814
816 { wxT("Edit/Other"),
817 { OrderingHint::Before, wxT("EditMetaData") } },
819};
820
821AttachedItem sAttachment2{ wxT("Tracks/Add/Add"),
823 Command( wxT("NewLabelTrack"), XXO("&Label Track"),
824 FN(OnNewLabelTrack), AudioIONotBusyFlag() )
825 )
826};
827
828}
829#undef FN
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
wxEvtHandler CommandHandlerObject
const ReservedCommandFlag & AudioIOBusyFlag()
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & WaveTracksExistFlag()
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
static CommandHandlerObject & findCommandHandler(AudacityProject &)
Definition: LabelMenus.cpp:702
WaveTrack::Region Region
Definition: LabelMenus.cpp:22
WaveTrack::Regions Regions
Definition: LabelMenus.cpp:23
#define FN(X)
Definition: LabelMenus.cpp:711
static const auto title
FileConfig * gPrefs
Definition: Prefs.cpp:71
TranslatableString label
Definition: TagsEditor.cpp:163
static std::once_flag flag
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
static AudioIO * Get()
Definition: AudioIO.cpp:140
static Clipboard & Get()
Definition: Clipboard.cpp:29
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
A LabelStruct holds information for ONE label in a LabelTrack.
Definition: LabelTrack.h:31
double getT1() const
Definition: LabelTrack.h:42
double getT0() const
Definition: LabelTrack.h:41
SelectedRegion selectedRegion
Definition: LabelTrack.h:71
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:89
static LabelTrack * Create(TrackList &trackList, const wxString &name)
Create a new LabelTrack with specified name and append it to the trackList.
Definition: LabelTrack.cpp:71
static LabelTrackView & Get(LabelTrack &)
static int DialogForLabelName(AudacityProject &project, const SelectedRegion &region, const wxString &initialValue, wxString &value)
int AddLabel(const SelectedRegion &region, const wxString &title={}, int restoreFocus=-1)
static void DoEditLabels(AudacityProject &project, LabelTrack *lt=nullptr, int index=-1)
static void ModifyAllProjectToolbarMenus()
Definition: Menus.cpp:592
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:909
int GetAudioIOToken() const
static ProjectAudioIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
bool IsSyncLocked() const
Defines a selected portion of a project.
double t1() const
double t0() const
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:98
virtual void SetSelected(bool s)
Definition: Track.cpp:88
virtual void Clear(double WXUNUSED(t0), double WXUNUSED(t1))=0
static void FinishCopy(const Track *n, Track *dest)
Definition: Track.cpp:395
R TypeSwitch(const Functions &...functions)
Use this function rather than testing track type explicitly and making down-casts.
Definition: Track.h:824
std::shared_ptr< Track > Holder
Definition: Track.h:361
bool Any() const
Definition: Track.cpp:380
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1330
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:483
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1429
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:467
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1446
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
void SplitDelete(double t0, double t1)
Definition: WaveTrack.cpp:1165
std::vector< Region > Regions
Definition: WaveTrack.h:75
void Join(double t0, double t1)
Definition: WaveTrack.cpp:1708
void Silence(double t0, double t1) override
Definition: WaveTrack.cpp:1572
void ClearAndAddCutLine(double t0, double t1)
Definition: WaveTrack.cpp:794
void Clear(double t0, double t1) override
Definition: WaveTrack.cpp:788
void Split(double t0, double t1)
Definition: WaveTrack.cpp:2517
void Disjoin(double t0, double t1)
Definition: WaveTrack.cpp:1637
Track::Holder CopyNonconst(double t0, double t1)
Definition: WaveTrack.cpp:782
Track::Holder SplitCut(double t0, double t1)
Definition: WaveTrack.cpp:642
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Definition: WaveTrack.cpp:716
Namespace for functions for Edit Label submenu.
Definition: LabelMenus.cpp:283
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< MenuItems > Items(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::shared_ptr< BaseItem > BaseItemSharedPtr
Definition: Registry.h:72
void SelectNone(AudacityProject &project)
int DoAddLabel(AudacityProject &project, const SelectedRegion &region, bool preserveFocus=false)
Definition: LabelMenus.cpp:53
void EditByLabel(AudacityProject &project, TrackList &tracks, const SelectedRegion &selectedRegion, EditFunction action)
Definition: LabelMenus.cpp:167
void GetRegionsByLabel(const TrackList &tracks, const SelectedRegion &selectedRegion, Regions &regions)
Definition: LabelMenus.cpp:122
std::function< Track::Holder(Track *, double, double)> EditDestFunction
Definition: LabelMenus.cpp:198
const ReservedCommandFlag & LabelsSelectedFlag()
Definition: LabelMenus.cpp:29
std::function< void(Track *, double, double)> EditFunction
Definition: LabelMenus.cpp:159
BaseItemSharedPtr LabelEditMenus()
Definition: LabelMenus.cpp:715
void EditClipboardByLabel(AudacityProject &project, TrackList &tracks, const SelectedRegion &selectedRegion, EditDestFunction action)
Definition: LabelMenus.cpp:206
std::vector< CommandFlagOptions > & Options()
Definition: Menus.cpp:535
void OnSplitLabels(const CommandContext &context)
Definition: LabelMenus.cpp:594
void OnCutLabels(const CommandContext &context)
Definition: LabelMenus.cpp:392
void OnToggleTypeToCreateLabel(const CommandContext &WXUNUSED(context))
Definition: LabelMenus.cpp:383
void OnNewLabelTrack(const CommandContext &context)
Definition: LabelMenus.cpp:680
void OnSilenceLabels(const CommandContext &context)
Definition: LabelMenus.cpp:541
void OnDisjoinLabels(const CommandContext &context)
Definition: LabelMenus.cpp:650
void OnAddLabel(const CommandContext &context)
Definition: LabelMenus.cpp:298
void OnSplitDeleteLabels(const CommandContext &context)
Definition: LabelMenus.cpp:508
void OnDeleteLabels(const CommandContext &context)
Definition: LabelMenus.cpp:449
void OnJoinLabels(const CommandContext &context)
Definition: LabelMenus.cpp:622
void OnPasteNewLabel(const CommandContext &context)
Definition: LabelMenus.cpp:321
void OnCopyLabels(const CommandContext &context)
Definition: LabelMenus.cpp:568
void OnAddLabelPlaying(const CommandContext &context)
Definition: LabelMenus.cpp:306
void OnSplitCutLabels(const CommandContext &context)
Definition: LabelMenus.cpp:473
void OnEditLabels(const CommandContext &context)
Definition: LabelMenus.cpp:292
Structure to hold region of a wavetrack and a comparison function for sortability.
Definition: WaveTrack.h:62