mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 07:39:42 +02:00
... and deduce whether to exclude from macros inside NewIdentifier, simplifying argument lists further Also fix the localization of "..." added to names by PluginMenus.cpp
659 lines
21 KiB
C++
659 lines
21 KiB
C++
#include "../AudioIOBase.h"
|
|
#include "../Clipboard.h"
|
|
#include "../CommonCommandFlags.h"
|
|
#include "../LabelTrack.h"
|
|
#include "../Menus.h"
|
|
#include "../Prefs.h"
|
|
#include "../ProjectAudioIO.h"
|
|
#include "../ProjectHistory.h"
|
|
#include "../ProjectWindow.h"
|
|
#include "../TrackPanelAx.h"
|
|
#include "../TrackPanel.h"
|
|
#include "../ViewInfo.h"
|
|
#include "../WaveTrack.h"
|
|
#include "../commands/CommandContext.h"
|
|
#include "../commands/CommandManager.h"
|
|
#include "../tracks/labeltrack/ui/LabelTrackView.h"
|
|
|
|
// private helper classes and functions
|
|
namespace {
|
|
|
|
//Adds label and returns index of label in labeltrack.
|
|
int DoAddLabel(
|
|
AudacityProject &project, const SelectedRegion ®ion,
|
|
bool preserveFocus = false)
|
|
{
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &trackFocus = TrackFocus::Get( project );
|
|
auto &trackPanel = TrackPanel::Get( project );
|
|
auto &trackFactory = TrackFactory::Get( project );
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
wxString title; // of label
|
|
|
|
bool useDialog;
|
|
gPrefs->Read(wxT("/GUI/DialogForNameNewLabel"), &useDialog, false);
|
|
if (useDialog) {
|
|
if (LabelTrackView::DialogForLabelName(
|
|
project, region, wxEmptyString, title) == wxID_CANCEL)
|
|
return -1; // index
|
|
}
|
|
|
|
// If the focused track is a label track, use that
|
|
const auto pFocusedTrack = trackFocus.Get();
|
|
|
|
// Look for a label track at or after the focused track
|
|
auto iter = pFocusedTrack
|
|
? tracks.Find(pFocusedTrack)
|
|
: tracks.Any().begin();
|
|
auto lt = * iter.Filter< LabelTrack >();
|
|
|
|
// If none found, start a NEW label track and use it
|
|
if (!lt)
|
|
lt = tracks.Add( trackFactory.NewLabelTrack() );
|
|
|
|
// LLL: Commented as it seemed a little forceful to remove users
|
|
// selection when adding the label. This does not happen if
|
|
// you select several tracks and the last one of those is a
|
|
// label track...typing a label will not clear the selections.
|
|
//
|
|
// SelectNone();
|
|
lt->SetSelected(true);
|
|
|
|
int index;
|
|
if (useDialog) {
|
|
index = lt->AddLabel(region, title);
|
|
}
|
|
else {
|
|
int focusTrackNumber = -1;
|
|
if (pFocusedTrack && preserveFocus) {
|
|
// Must remember the track to re-focus after finishing a label edit.
|
|
// do NOT identify it by a pointer, which might dangle! Identify
|
|
// by position.
|
|
focusTrackNumber = pFocusedTrack->GetIndex();
|
|
}
|
|
index =
|
|
LabelTrackView::Get( *lt ).AddLabel(region, title, focusTrackNumber);
|
|
}
|
|
|
|
ProjectHistory::Get( project ).PushState(_("Added label"), _("Label"));
|
|
|
|
if (!useDialog) {
|
|
TrackFocus::Get(project).Set(lt);
|
|
lt->EnsureVisible();
|
|
}
|
|
trackPanel.SetFocus();
|
|
|
|
return index;
|
|
}
|
|
|
|
//get regions selected by selected labels
|
|
//removes unnecessary regions, overlapping regions are merged
|
|
void GetRegionsByLabel(
|
|
const TrackList &tracks, const SelectedRegion &selectedRegion,
|
|
Regions ®ions )
|
|
{
|
|
//determine labeled regions
|
|
for (auto lt : tracks.Selected< const LabelTrack >()) {
|
|
for (int i = 0; i < lt->GetNumLabels(); i++)
|
|
{
|
|
const LabelStruct *ls = lt->GetLabel(i);
|
|
if (ls->selectedRegion.t0() >= selectedRegion.t0() &&
|
|
ls->selectedRegion.t1() <= selectedRegion.t1())
|
|
regions.push_back(Region(ls->getT0(), ls->getT1()));
|
|
}
|
|
}
|
|
|
|
//anything to do ?
|
|
if( regions.size() == 0 )
|
|
return;
|
|
|
|
//sort and remove unnecessary regions
|
|
std::sort(regions.begin(), regions.end());
|
|
unsigned int selected = 1;
|
|
while( selected < regions.size() )
|
|
{
|
|
const Region &cur = regions.at( selected );
|
|
Region &last = regions.at( selected - 1 );
|
|
if( cur.start < last.end )
|
|
{
|
|
if( cur.end > last.end )
|
|
last.end = cur.end;
|
|
regions.erase( regions.begin() + selected );
|
|
}
|
|
else
|
|
++selected;
|
|
}
|
|
}
|
|
|
|
using EditFunction = void (WaveTrack::*)(double, double);
|
|
|
|
//Executes the edit function on all selected wave tracks with
|
|
//regions specified by selected labels
|
|
//If No tracks selected, function is applied on all tracks
|
|
//If the function replaces the selection with audio of a different length,
|
|
// bSyncLockedTracks should be set true to perform the same action on sync-lock
|
|
// selected tracks.
|
|
void EditByLabel(
|
|
TrackList &tracks, const SelectedRegion &selectedRegion,
|
|
EditFunction action, bool bSyncLockedTracks )
|
|
{
|
|
Regions regions;
|
|
|
|
GetRegionsByLabel( tracks, selectedRegion, regions );
|
|
if( regions.size() == 0 )
|
|
return;
|
|
|
|
// if at least one wave track is selected
|
|
// apply only on the selected track
|
|
const bool allTracks = (tracks.Selected< WaveTrack >()).empty();
|
|
|
|
//Apply action on wavetracks starting from
|
|
//labeled regions in the end. This is to correctly perform
|
|
//actions like 'Delete' which collapse the track area.
|
|
for (auto wt : tracks.Any<WaveTrack>())
|
|
{
|
|
if (allTracks || wt->GetSelected() ||
|
|
(bSyncLockedTracks && wt->IsSyncLockSelected()))
|
|
{
|
|
for (int i = (int)regions.size() - 1; i >= 0; i--) {
|
|
const Region ®ion = regions.at(i);
|
|
(wt->*action)(region.start, region.end);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
using EditDestFunction = std::shared_ptr<Track> (WaveTrack::*)(double, double);
|
|
|
|
//Executes the edit function on all selected wave tracks with
|
|
//regions specified by selected labels
|
|
//If No tracks selected, function is applied on all tracks
|
|
//Functions copy the edited regions to clipboard, possibly in multiple tracks
|
|
//This probably should not be called if *action() changes the timeline, because
|
|
// the copy needs to happen by track, and the timeline change by group.
|
|
void EditClipboardByLabel( AudacityProject &project,
|
|
TrackList &tracks, const SelectedRegion &selectedRegion,
|
|
EditDestFunction action )
|
|
{
|
|
Regions regions;
|
|
|
|
GetRegionsByLabel( tracks, selectedRegion, regions );
|
|
if( regions.size() == 0 )
|
|
return;
|
|
|
|
// if at least one wave track is selected
|
|
// apply only on the selected track
|
|
const bool allTracks = (tracks.Selected< WaveTrack >()).empty();
|
|
|
|
auto &clipboard = Clipboard::Get();
|
|
clipboard.Clear();
|
|
|
|
auto pNewClipboard = TrackList::Create();
|
|
auto &newClipboard = *pNewClipboard;
|
|
|
|
//Apply action on wavetracks starting from
|
|
//labeled regions in the end. This is to correctly perform
|
|
//actions like 'Cut' which collapse the track area.
|
|
|
|
for(auto wt :
|
|
tracks.Any<WaveTrack>()
|
|
+ (allTracks ? &Track::Any : &Track::IsSelected)
|
|
) {
|
|
// This track accumulates the needed clips, right to left:
|
|
Track::Holder merged;
|
|
for( int i = (int)regions.size() - 1; i >= 0; i-- )
|
|
{
|
|
const Region ®ion = regions.at(i);
|
|
auto dest = ( wt->*action )( region.start, region.end );
|
|
if( dest )
|
|
{
|
|
Track::FinishCopy( wt, dest.get() );
|
|
if( !merged )
|
|
merged = dest;
|
|
else
|
|
{
|
|
// Paste to the beginning; unless this is the first region,
|
|
// offset the track to account for time between the regions
|
|
if (i < (int)regions.size() - 1)
|
|
merged->Offset(
|
|
regions.at(i + 1).start - region.end);
|
|
|
|
// dest may have a placeholder clip at the end that is
|
|
// removed when pasting, which is okay because we proceed
|
|
// right to left. Any placeholder already in merged is kept.
|
|
// Only the rightmost placeholder is important in the final
|
|
// result.
|
|
merged->Paste( 0.0 , dest.get() );
|
|
}
|
|
}
|
|
else
|
|
// nothing copied but there is a 'region', so the 'region' must
|
|
// be a 'point label' so offset
|
|
if (i < (int)regions.size() - 1)
|
|
if (merged)
|
|
merged->Offset(
|
|
regions.at(i + 1).start - region.end);
|
|
}
|
|
if( merged )
|
|
newClipboard.Add( merged );
|
|
}
|
|
|
|
// Survived possibility of exceptions. Commit changes to the clipboard now.
|
|
clipboard.Assign( std::move( newClipboard ),
|
|
regions.front().start, regions.back().end, &project );
|
|
}
|
|
|
|
}
|
|
|
|
/// Namespace for functions for Edit Label submenu
|
|
namespace LabelEditActions {
|
|
|
|
// exported helper functions
|
|
// none
|
|
|
|
// Menu handler functions
|
|
|
|
struct Handler : CommandHandlerObject {
|
|
|
|
void OnEditLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
LabelTrackView::DoEditLabels(project);
|
|
}
|
|
|
|
void OnAddLabel(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
|
|
DoAddLabel(project, selectedRegion);
|
|
}
|
|
|
|
void OnAddLabelPlaying(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto token = ProjectAudioIO::Get( project ).GetAudioIOToken();
|
|
|
|
auto gAudioIO = AudioIOBase::Get();
|
|
if (token > 0 &&
|
|
gAudioIO->IsStreamActive(token)) {
|
|
double indicator = gAudioIO->GetStreamTime();
|
|
DoAddLabel(project, SelectedRegion(indicator, indicator), true);
|
|
}
|
|
}
|
|
|
|
// Creates a NEW label in each selected label track with text from the system
|
|
// clipboard
|
|
void OnPasteNewLabel(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &trackFactory = TrackFactory::Get( project );
|
|
auto &trackPanel = TrackPanel::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
bool bPastedSomething = false;
|
|
|
|
{
|
|
auto trackRange = tracks.Selected< const LabelTrack >();
|
|
if (trackRange.empty())
|
|
{
|
|
// If there are no selected label tracks, try to choose the first label
|
|
// track after some other selected track
|
|
Track *t = *tracks.Selected().begin()
|
|
.Filter( &Track::Any )
|
|
.Filter<LabelTrack>();
|
|
|
|
// If no match found, add one
|
|
if (!t)
|
|
t = tracks.Add( trackFactory.NewLabelTrack() );
|
|
|
|
// Select this track so the loop picks it up
|
|
t->SetSelected(true);
|
|
}
|
|
}
|
|
|
|
LabelTrack *plt = NULL; // the previous track
|
|
for ( auto lt : tracks.Selected< LabelTrack >() )
|
|
{
|
|
// Unselect the last label, so we'll have just one active label when
|
|
// we're done
|
|
if (plt)
|
|
LabelTrackView::Get( *plt ).SetSelectedIndex( -1 );
|
|
|
|
// Add a NEW label, paste into it
|
|
// Paul L: copy whatever defines the selected region, not just times
|
|
auto &view = LabelTrackView::Get( *lt );
|
|
view.AddLabel(selectedRegion);
|
|
if (view.PasteSelectedText( context.project, selectedRegion.t0(),
|
|
selectedRegion.t1() ))
|
|
bPastedSomething = true;
|
|
|
|
// Set previous track
|
|
plt = lt;
|
|
}
|
|
|
|
// plt should point to the last label track pasted to -- ensure it's visible
|
|
// and set focus
|
|
if (plt) {
|
|
TrackFocus::Get(project).Set(plt);
|
|
plt->EnsureVisible();
|
|
trackPanel.SetFocus();
|
|
}
|
|
|
|
if (bPastedSomething) {
|
|
ProjectHistory::Get( project ).PushState(
|
|
_("Pasted from the clipboard"), _("Paste Text to New Label"));
|
|
}
|
|
}
|
|
|
|
void OnToggleTypeToCreateLabel(const CommandContext &WXUNUSED(context) )
|
|
{
|
|
bool typeToCreateLabel;
|
|
gPrefs->Read(wxT("/GUI/TypeToCreateLabel"), &typeToCreateLabel, false);
|
|
gPrefs->Write(wxT("/GUI/TypeToCreateLabel"), !typeToCreateLabel);
|
|
gPrefs->Flush();
|
|
MenuManager::ModifyAllProjectToolbarMenus();
|
|
}
|
|
|
|
void OnCutLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
// Because of grouping the copy may need to operate on different tracks than
|
|
// the clear, so we do these actions separately.
|
|
EditClipboardByLabel( project,
|
|
tracks, selectedRegion, &WaveTrack::CopyNonconst );
|
|
|
|
if( gPrefs->Read( wxT( "/GUI/EnableCutLines" ), ( long )0 ) )
|
|
EditByLabel(
|
|
tracks, selectedRegion, &WaveTrack::ClearAndAddCutLine, true );
|
|
else
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Clear, true );
|
|
|
|
selectedRegion.collapseToT0();
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) past tense. Audacity has just cut the labeled audio
|
|
regions.*/
|
|
_( "Cut labeled audio regions to clipboard" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Cut Labeled Audio" ) );
|
|
}
|
|
|
|
void OnDeleteLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Clear, true );
|
|
|
|
selectedRegion.collapseToT0();
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) Audacity has just deleted the labeled audio regions*/
|
|
_( "Deleted labeled audio regions" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Delete Labeled Audio" ) );
|
|
}
|
|
|
|
void OnSplitCutLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditClipboardByLabel( project,
|
|
tracks, selectedRegion, &WaveTrack::SplitCut );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) Audacity has just split cut the labeled audio
|
|
regions*/
|
|
_( "Split Cut labeled audio regions to clipboard" ),
|
|
/* i18n-hint: (verb) Do a special kind of cut on the labels*/
|
|
_( "Split Cut Labeled Audio" ) );
|
|
}
|
|
|
|
void OnSplitDeleteLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::SplitDelete, false );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) Audacity has just done a special kind of DELETE on
|
|
the labeled audio regions */
|
|
_( "Split Deleted labeled audio regions" ),
|
|
/* i18n-hint: (verb) Do a special kind of DELETE on labeled audio
|
|
regions */
|
|
_( "Split Delete Labeled Audio" ) );
|
|
}
|
|
|
|
void OnSilenceLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Silence, false );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb)*/
|
|
_( "Silenced labeled audio regions" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Silence Labeled Audio" ) );
|
|
}
|
|
|
|
void OnCopyLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditClipboardByLabel( project,
|
|
tracks, selectedRegion, &WaveTrack::CopyNonconst );
|
|
|
|
ProjectHistory::Get( project ).PushState( _( "Copied labeled audio regions to clipboard" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Copy Labeled Audio" ) );
|
|
}
|
|
|
|
void OnSplitLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Split, false );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) past tense. Audacity has just split the labeled
|
|
audio (a point or a region)*/
|
|
_( "Split labeled audio (points or regions)" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Split Labeled Audio" ) );
|
|
}
|
|
|
|
void OnJoinLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Join, false );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) Audacity has just joined the labeled audio (points or
|
|
regions) */
|
|
_( "Joined labeled audio (points or regions)" ),
|
|
/* i18n-hint: (verb) */
|
|
_( "Join Labeled Audio" ) );
|
|
}
|
|
|
|
void OnDisjoinLabels(const CommandContext &context)
|
|
{
|
|
auto &project = context.project;
|
|
auto &tracks = TrackList::Get( project );
|
|
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
|
|
auto &window = ProjectWindow::Get( project );
|
|
|
|
if( selectedRegion.isPoint() )
|
|
return;
|
|
|
|
EditByLabel( tracks, selectedRegion, &WaveTrack::Disjoin, false );
|
|
|
|
ProjectHistory::Get( project ).PushState(
|
|
/* i18n-hint: (verb) Audacity has just detached the labeled audio regions.
|
|
This message appears in history and tells you about something
|
|
Audacity has done.*/
|
|
_( "Detached labeled audio regions" ),
|
|
/* i18n-hint: (verb)*/
|
|
_( "Detach Labeled Audio" ) );
|
|
}
|
|
|
|
}; // struct Handler
|
|
|
|
} // namespace
|
|
|
|
static CommandHandlerObject &findCommandHandler(AudacityProject &) {
|
|
// Handler is not stateful. Doesn't need a factory registered with
|
|
// AudacityProject.
|
|
static LabelEditActions::Handler instance;
|
|
return instance;
|
|
};
|
|
|
|
// Menu definitions
|
|
|
|
#define FN(X) findCommandHandler, \
|
|
static_cast<CommandFunctorPointer>(& LabelEditActions::Handler :: X)
|
|
|
|
MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & )
|
|
{
|
|
using namespace MenuTable;
|
|
using Options = CommandManager::Options;
|
|
|
|
static const auto checkOff = Options{}.CheckState( false );
|
|
|
|
static const auto NotBusyLabelsAndWaveFlags =
|
|
AudioIONotBusyFlag |
|
|
LabelsSelectedFlag | WaveTracksExistFlag | TimeSelectedFlag;
|
|
|
|
// Returns TWO menus.
|
|
|
|
return Items(
|
|
|
|
Menu( _("&Labels"),
|
|
Command( wxT("EditLabels"), XXO("&Edit Labels..."), FN(OnEditLabels),
|
|
AudioIONotBusyFlag ),
|
|
|
|
Separator(),
|
|
|
|
Command( wxT("AddLabel"), XXO("Add Label at &Selection"),
|
|
FN(OnAddLabel), AlwaysEnabledFlag, wxT("Ctrl+B") ),
|
|
Command( wxT("AddLabelPlaying"),
|
|
XXO("Add Label at &Playback Position"),
|
|
FN(OnAddLabelPlaying), AudioIOBusyFlag,
|
|
#ifdef __WXMAC__
|
|
wxT("Ctrl+.")
|
|
#else
|
|
wxT("Ctrl+M")
|
|
#endif
|
|
),
|
|
Command( wxT("PasteNewLabel"), XXO("Paste Te&xt to New Label"),
|
|
FN(OnPasteNewLabel),
|
|
AudioIONotBusyFlag, wxT("Ctrl+Alt+V") ),
|
|
|
|
Separator(),
|
|
|
|
Command( wxT("TypeToCreateLabel"),
|
|
XXO("&Type to Create a Label (on/off)"),
|
|
FN(OnToggleTypeToCreateLabel), AlwaysEnabledFlag, checkOff )
|
|
), // first menu
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
Menu( _("La&beled Audio"),
|
|
/* i18n-hint: (verb)*/
|
|
Command( wxT("CutLabels"), XXO("&Cut"), FN(OnCutLabels),
|
|
AudioIONotBusyFlag | LabelsSelectedFlag | WaveTracksExistFlag |
|
|
TimeSelectedFlag | IsNotSyncLockedFlag,
|
|
Options{ wxT("Alt+X"), XO("Label Cut") } ),
|
|
Command( wxT("DeleteLabels"), XXO("&Delete"), FN(OnDeleteLabels),
|
|
AudioIONotBusyFlag | LabelsSelectedFlag | WaveTracksExistFlag |
|
|
TimeSelectedFlag | IsNotSyncLockedFlag,
|
|
Options{ wxT("Alt+K"), XO("Label Delete") } ),
|
|
|
|
Separator(),
|
|
|
|
/* i18n-hint: (verb) A special way to cut out a piece of audio*/
|
|
Command( wxT("SplitCutLabels"), XXO("&Split Cut"),
|
|
FN(OnSplitCutLabels), NotBusyLabelsAndWaveFlags,
|
|
Options{ wxT("Alt+Shift+X"), XO("Label Split Cut") } ),
|
|
Command( wxT("SplitDeleteLabels"), XXO("Sp&lit Delete"),
|
|
FN(OnSplitDeleteLabels), NotBusyLabelsAndWaveFlags,
|
|
Options{ wxT("Alt+Shift+K"), XO("Label Split Delete") } ),
|
|
|
|
Separator(),
|
|
|
|
Command( wxT("SilenceLabels"), XXO("Silence &Audio"),
|
|
FN(OnSilenceLabels), NotBusyLabelsAndWaveFlags,
|
|
Options{ wxT("Alt+L"), XO("Label Silence") } ),
|
|
/* i18n-hint: (verb)*/
|
|
Command( wxT("CopyLabels"), XXO("Co&py"), FN(OnCopyLabels),
|
|
NotBusyLabelsAndWaveFlags,
|
|
Options{ wxT("Alt+Shift+C"), XO("Label Copy") } ),
|
|
|
|
Separator(),
|
|
|
|
/* i18n-hint: (verb)*/
|
|
Command( wxT("SplitLabels"), XXO("Spli&t"), FN(OnSplitLabels),
|
|
AudioIONotBusyFlag | LabelsSelectedFlag | WaveTracksExistFlag,
|
|
Options{ wxT("Alt+I"), XO("Label Split") } ),
|
|
/* i18n-hint: (verb)*/
|
|
Command( wxT("JoinLabels"), XXO("&Join"), FN(OnJoinLabels),
|
|
NotBusyLabelsAndWaveFlags,
|
|
Options{ wxT("Alt+J"), XO("Label Join") } ),
|
|
Command( wxT("DisjoinLabels"), XXO("Detac&h at Silences"),
|
|
FN(OnDisjoinLabels), NotBusyLabelsAndWaveFlags,
|
|
wxT("Alt+Shift+J") )
|
|
) // second menu
|
|
|
|
); // two menus
|
|
}
|
|
|
|
#undef FN
|