2#include "../AdornedRulerPanel.h"
3#include "../Clipboard.h"
4#include "../CommonCommandFlags.h"
5#include "../LabelTrack.h"
7#include "../NoteTrack.h"
12#include "../ProjectSettings.h"
13#include "../ProjectWindow.h"
14#include "../ProjectWindows.h"
15#include "../SelectUtilities.h"
16#include "../SyncLock.h"
17#include "../TrackPanel.h"
18#include "../TrackPanelAx.h"
21#include "../WaveTrack.h"
22#include "../commands/CommandContext.h"
23#include "../commands/CommandManager.h"
25#include "../export/Export.h"
26#include "../prefs/PrefsDialog.h"
27#include "../tracks/labeltrack/ui/LabelTrackView.h"
28#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
29#include "../widgets/AudacityMessageBox.h"
30#include "../widgets/VetoDialogHook.h"
50 for (
auto pLabelTrack : tracks.Any<
LabelTrack>())
57 if (view.PasteSelectedText( project, selectedRegion.t0(),
58 selectedRegion.t1() ))
61 .
PushState(
XO(
"Pasted text from the clipboard"),
XO(
"Paste"));
65 if (view.CalcCursorX( project, &x )) {
66 window.ScrollIntoView(x);
87 if (tracks.Selected())
92 auto clipTrackRange = clipboard.GetTracks().Any<
const Track >();
93 if (clipTrackRange.empty())
96 Track* pFirstNewTrack = NULL;
97 for (
auto pClip : clipTrackRange) {
98 auto pNewTrack = pClip->
PasteInto( project );
99 bool newTrack = (pNewTrack.use_count() == 1);
103 pFirstNewTrack = pNewTrack.get();
118 selectedRegion.setTimes(
126 if (pFirstNewTrack) {
144 auto &project = context.
project;
156 if (trackPanel.IsMouseCaptured()) {
164 auto t = *tracks.Selected().begin();
166 t = *tracks.Any().begin();
175 auto &project = context.
project;
186 if (trackPanel.IsMouseCaptured()) {
194 auto t = *tracks.Selected().begin();
196 t = *tracks.Any().begin();
205 auto &project = context.
project;
216 for (
auto lt : tracks.Selected<
LabelTrack >()) {
218 if (view.CutSelectedText( context.
project )) {
219 trackPanel.Refresh(
false);
226 for (
auto wt : tracks.Any<
WaveTrack>()) {
228 if (view.CutSelectedText(context.
project)) {
229 trackPanel.Refresh(
false);
238 auto &newClipboard = *pNewClipboard;
240 tracks.Selected().Visit(
244 auto dest = n->
Cut(selectedRegion.t0(),
245 selectedRegion.t1());
251 auto dest = n->
Copy(selectedRegion.t0(),
252 selectedRegion.t1());
260 std::move( newClipboard ),
263 project.shared_from_this()
278 if (
gPrefs->Read(wxT(
"/GUI/EnableCutLines"), (long)0)) {
281 selectedRegion.t1());
288 n->
Clear(selectedRegion.t0(), selectedRegion.t1());
292 selectedRegion.collapseToT0();
299 ruler.DrawOverlays(
true );
304 auto &project = context.
project;
309 for (
auto n : tracks.Any()) {
310 if (!n->SupportsBasicEditing())
313 n->Clear(selectedRegion.t0(), selectedRegion.t1());
317 double seconds = selectedRegion.duration();
319 selectedRegion.collapseToT0();
322 XO(
"Deleted %.2f seconds at t=%.2f")
323 .
Format( seconds, selectedRegion.t0()),
330 auto &project = context.
project;
335 for (
auto lt : tracks.Selected<
LabelTrack >()) {
337 if (view.CopySelectedText( context.
project )) {
344 for (
auto wt : tracks.Any<
WaveTrack>()) {
346 if (view.CopySelectedText(context.
project)) {
355 auto &newClipboard = *pNewClipboard;
357 for (
auto n : tracks.Selected()) {
358 if (n->SupportsBasicEditing()) {
359 auto dest = n->Copy(selectedRegion.t0(),
360 selectedRegion.t1());
366 clipboard.Assign( std::move( newClipboard ),
367 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
370 trackPanel.Refresh(
false);
375 double sel0 = 0.0, sel1 = 0.0;
380 auto &selectedRegion = *pRegion;
381 sel0 = selectedRegion.t0();
382 sel1 = selectedRegion.t1();
388 sel0 = selectedRegion.
t0();
389 sel1 = selectedRegion.t1();
392 return { sel0, sel1 };
397 auto &project = context.
project;
401 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
405 auto isSyncLocked =
settings.IsSyncLocked();
413 for (
auto wt : tracks.Any<
WaveTrack>()) {
415 if (view.PasteText(context.
project)) {
416 trackPanel.Refresh(
false);
426 auto clipTrackRange = clipboard.GetTracks().Any<
const Track >();
427 if (clipTrackRange.empty())
434 auto pN = tracks.Any().begin();
437 const Track *lastClipBeforeMismatch = NULL;
438 const Track *mismatchedClip = NULL;
439 const Track *prevClip = NULL;
441 bool bAdvanceClipboard =
true;
442 bool bPastedSomething =
false;
445 bPastedSomething =
true;
451 auto pC = clipTrackRange.begin();
452 size_t nnChannels=0, ncChannels=0;
456 if (n->GetSelected()) {
457 bAdvanceClipboard =
true;
460 if (!c->SameKindAs(*n)) {
461 if (!mismatchedClip) {
462 lastClipBeforeMismatch = prevClip;
465 bAdvanceClipboard =
false;
466 c = lastClipBeforeMismatch;
470 while (c && !c->SameKindAs(*n)) {
480 while (n && (!c->SameKindAs(*n) || !n->GetSelected()))
484 auto newT1 = t0 + clipboard.Duration();
485 if (t1 != newT1 && t1 <= n->GetEndTime()) {
487 bPastedSomething =
true;
504 XO(
"Pasting one type of track into another is not allowed."),
506 "Error:_Copying_or_Pasting"
511 if ( n->IsLeader() ) {
512 wxASSERT( c->IsLeader() );
515 ncChannels = cChannels.size();
517 nnChannels = nChannels.size();
523 if (ncChannels > nnChannels)
525 if (ncChannels > 2) {
535 XO(
"Copying stereo audio into a mono track is not allowed."),
537 "Error:_Copying_or_Pasting"
545 wxASSERT( n && c && n->SameKindAs(*c) );
548 pasteWaveTrack(wn,
static_cast<const WaveTrack *
>(c));
555 ln->ShiftLabelsOnInsert( clipboard.Duration(), t0 );
557 bPastedSomething |= ln->PasteOver(t0, c);
560 bPastedSomething =
true;
573 while (nnChannels > 0 && ncChannels == 0)
580 pasteWaveTrack(wn, c);
584 bPastedSomething =
true;
590 if (bAdvanceClipboard) {
597 auto newT1 = t0 + clipboard.Duration();
598 if (t1 != newT1 && t1 <= n->GetEndTime()) {
600 bPastedSomething =
true;
613 *clipboard.GetTracks().Any<
const WaveTrack >().rbegin();
615 tracks.Any().StartingWith(*pN).Visit(
617 if (!wt->GetSelected())
618 return fallthrough();
621 pasteWaveTrack(wt, wc);
624 auto tmp = wt->EmptyCopy( pSampleBlockFactory );
625 tmp->InsertSilence( 0.0,
627 clipboard.Duration() );
630 pasteWaveTrack(wt, tmp.get());
635 return fallthrough();
642 clipboard.Duration(), t0);
646 n->SyncLockAdjust(t1, t0 + clipboard.Duration() );
653 if (bPastedSomething)
656 .
setTimes( t0, t0 + clipboard.Duration() );
664 ff->LinkConsistencyFix();
671 auto &project = context.
project;
677 auto range = tracks.Selected();
678 auto last = *range.rbegin();
679 for (
auto n : range) {
680 if (!n->SupportsBasicEditing())
684 auto dest = n->Copy(selectedRegion.t0(),
685 selectedRegion.t1(),
false);
687 dest->SetOffset(wxMax(selectedRegion.t0(), n->GetOffset()));
701 auto &project = context.
project;
710 auto &newClipboard = *pNewClipboard;
714 tracks.Selected().Visit(
718 selectedRegion.t1());
724 dest = n->
Copy(selectedRegion.t0(),
725 selectedRegion.t1());
726 n->
Silence(selectedRegion.t0(),
727 selectedRegion.t1());
735 clipboard.Assign( std::move( newClipboard ),
736 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
739 .
PushState(
XO(
"Split-cut to the clipboard"),
XO(
"Split Cut"));
744 auto &project = context.
project;
749 tracks.Selected().Visit(
752 selectedRegion.t1());
755 if (n->SupportsBasicEditing())
756 n->Silence(selectedRegion.t0(),
757 selectedRegion.t1());
762 XO(
"Split-deleted %.2f seconds at t=%.2f")
763 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
769 auto &project = context.
project;
773 for (
auto n : tracks.Selected<
WaveTrack >() )
774 n->Silence(selectedRegion.t0(), selectedRegion.t1());
777 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
778 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
780 XC(
"Silence",
"command"));
785 auto &project = context.
project;
790 if (selectedRegion.isPoint())
793 tracks.Selected().Visit(
796 wt->
Trim(selectedRegion.t0(),
797 selectedRegion.t1());
802 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
803 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
809 auto &project = context.
project;
812 auto [sel0, sel1] = FindSelection(context);
815 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
817 pChannel->Split( sel0, sel1 );
823 for (
auto wt : tracks.Selected<
WaveTrack >())
824 wt->Split( sel0, sel1 );
878 auto &project = context.
project;
886 auto range = tracks.Selected();
887 auto last = *range.rbegin();
888 for (
auto track : range) {
896 selectedRegion.t0()));
898 selectedRegion.t1()));
901 dest->SetOffset(wxMax(newt0, offset));
910 dest = n->Cut(viewInfo.selectedRegion.t0(),
911 viewInfo.selectedRegion.t1());
913 dest->SetOffset(wxMax(0, n->GetOffset()));
929 auto &project = context.
project;
934 for (
auto wt : tracks.Selected<
WaveTrack >())
935 wt->Join(selectedRegion.t0(),
936 selectedRegion.t1());
939 XO(
"Joined %.2f seconds at t=%.2f")
940 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
946 auto &project = context.
project;
951 for (
auto wt : tracks.Selected<
WaveTrack >())
952 wt->Disjoin(selectedRegion.t0(),
953 selectedRegion.t1());
956 XO(
"Detached %.2f seconds at t=%.2f")
957 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
963 auto &project = context.
project;
965 XO(
"Edit Metadata Tags"),
XO(
"Metadata Tags"),
true);
970 auto &project = context.
project;
988#if defined(__WXGTK__)
996 wxRect r = window.GetRect();
997 window.SetSize(wxSize(1,1));
998 window.SetSize(r.GetSize());
1008 auto &project = context.
project;
1009 auto &selectedRegion = project.GetViewInfo().selectedRegion;
1011 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
1013 selectedRegion.setT1(
1014 selectedRegion.t0() +
1015 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1037#define FN(X) (& EditActions::Handler :: X)
1049 if ( !range.empty() )
1070 static const auto NotBusyTimeAndTracksFlags =
1074 static constexpr auto redoKey =
1084 static constexpr auto prefKey =
1094 Menu( wxT(
"Edit"),
XXO(
"&Edit"),
1102 Special( wxT(
"UndoItemsUpdateStep"),
1125 Command( wxT(
"Duplicate"),
XXO(
"Duplic&ate"),
FN(OnDuplicate),
1126 NotBusyTimeAndTracksFlags, wxT(
"Ctrl+D") ),
1129 Menu( wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1132 Command( wxT(
"SplitCut"),
XXO(
"Spl&it Cut"),
FN(OnSplitCut),
1133 NotBusyTimeAndTracksFlags,
1134 Options{ wxT(
"Ctrl+Alt+X") } ),
1136 Command( wxT(
"SplitDelete"),
XXO(
"Split D&elete"),
FN(OnSplitDelete),
1137 NotBusyTimeAndTracksFlags,
1138 Options{ wxT(
"Ctrl+Alt+K") } )
1143 Command( wxT(
"Silence"),
XXO(
"Silence Audi&o"),
FN(OnSilence),
1159 Menu( wxT(
"Clip"),
XXO(
"Audi&o Clips"),
1165 Command( wxT(
"SplitNew"),
XXO(
"Split Ne&w"),
FN(OnSplitNew),
1167 Options{ wxT(
"Ctrl+Alt+I") } )
1173 NotBusyTimeAndTracksFlags, wxT(
"Ctrl+J") ),
1174 Command( wxT(
"Disjoin"),
XXO(
"Detac&h at Silences"),
FN(OnDisjoin),
1175 NotBusyTimeAndTracksFlags, wxT(
"Ctrl+Alt+J") )
1181 Command( wxT(
"EditMetaData"),
XXO(
"&Metadata..."),
FN(OnEditMetadata),
1193 Command( wxT(
"Preferences"),
XXO(
"Pre&ferences..."),
FN(OnPreferences),
1209 static const auto flags =
1213 Menu( wxT(
"Edit"),
XXO(
"&Edit"),
1214 Command( wxT(
"DeleteKey"),
XXO(
"&Delete Key"),
FN(OnDelete),
1217 Command( wxT(
"DeleteKey2"),
XXO(
"Delete Key&2"),
FN(OnDelete),
1263 wxT(
"Optional/Extra/Part1"),
@ 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)
std::bitset< NCommandFlags > CommandFlag
wxEvtHandler CommandHandlerObject
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)
auto Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
#define QUANTIZED_TIME(time, rate)
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()
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...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
TemporarySelection temporarySelection
AudacityProject & project
static bool DoEditMetadata(AudacityProject &project, const TranslatableString &title, const TranslatableString &shortUndoDescription, bool force)
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).
void ShiftLabelsOnInsert(double length, double pt)
void Clear(double t0, double t1) override
static LabelTrackView & Get(LabelTrack &)
bool IsTextSelected(AudacityProject &project) const
int GetTextEditIndex(AudacityProject &project) const
A Track that is used for Midi notes. (Somewhat old code).
Track::Holder Cut(double t0, double t1) override
void Clear(double t0, double t1) override
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
bool setTimes(double t0, double t1)
Unit slope but with either a jump (pasting more) or a flat interval (pasting less)
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)
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.
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
A MessageBoxException that shows a given, unvarying string.
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
static bool IsSyncLockSelected(const Track *pTrack)
Abstract base class for an object holding data associated with points on a time axis.
void EnsureVisible(bool modifyState=false)
virtual void SetSelected(bool s)
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)
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
virtual void SyncLockAdjust(double oldT1, double newT1)
std::shared_ptr< Track > Holder
Continuation<> Fallthrough
Type of arguments passed as optional second parameter to TypeSwitch<void>() cases.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
static TrackPanel & Get(AudacityProject &project)
static UndoManager & Get(AudacityProject &project)
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
static WaveTrackFactory & Get(AudacityProject &project)
A Track that contains audio waveform data.
void SplitDelete(double t0, double t1)
void Silence(double t0, double t1) override
void ClearAndAddCutLine(double t0, double t1)
double GetOffset() const override
void Trim(double t0, double t1)
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Track::Holder SplitCut(double t0, double t1)
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
static WaveTrackView & Get(WaveTrack &track)
std::shared_ptr< BaseItem > BaseItemSharedPtr
void DoSelectAllAudio(AudacityProject &project)
void OnSplitCut(const CommandContext &context)
void OnCopy(const CommandContext &context)
void OnTrim(const CommandContext &context)
void OnPreferences(const CommandContext &context)
void OnSilence(const CommandContext &context)
void OnRedo(const CommandContext &context)
std::pair< double, double > FindSelection(const CommandContext &context)
void OnDisjoin(const CommandContext &context)
void OnSplit(const CommandContext &context)
void OnEditMetadata(const CommandContext &context)
void OnDelete(const CommandContext &context)
void OnSplitNew(const CommandContext &context)
void OnCut(const CommandContext &context)
void OnDuplicate(const CommandContext &context)
void OnPaste(const CommandContext &context)
void OnSplitDelete(const CommandContext &context)
void OnUndo(const CommandContext &context)
void OnJoin(const CommandContext &context)
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.