2#include "../AdornedRulerPanel.h"
3#include "../Clipboard.h"
4#include "../CommonCommandFlags.h"
5#include "../LabelTrack.h"
7#include "../NoteTrack.h"
11#include "../ProjectWindow.h"
12#include "../ProjectWindows.h"
13#include "../SelectUtilities.h"
15#include "../TrackPanel.h"
16#include "../TrackPanelAx.h"
22#include "../commands/CommandContext.h"
23#include "../commands/CommandManager.h"
25#include "../prefs/PrefsDialog.h"
26#include "../prefs/TracksBehaviorsPrefs.h"
27#include "../tracks/labeltrack/ui/LabelTrackView.h"
28#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
30#include "../widgets/VetoDialogHook.h"
31#include "../AudioPasteDialog.h"
53 for (
auto pLabelTrack : tracks.Any<
LabelTrack>())
60 if (view.PasteSelectedText( project, selectedRegion.t0(),
61 selectedRegion.t1() ))
64 .
PushState(
XO(
"Pasted text from the clipboard"),
XO(
"Paste"));
68 if (view.CalcCursorX( project, &x )) {
69 window.ScrollIntoView(x);
93 const std::function<
void(
const WaveTrack& waveTrack)>& f)
104 auto srcTrack = srcTrackRange.begin();
105 auto dstTrack = dstTrackRange.begin();
106 auto lastCopiedTrack = srcTrack;
107 while(dstTrack != dstTrackRange.end() && srcTrack != srcTrackRange.end())
109 if(!(*dstTrack)->GetSelected())
118 while(srcChannelCount > 0 && dstChannelCount > 0)
122 lastCopiedTrack = srcTrack;
129 while(dstChannelCount > 0)
131 f(**lastCopiedTrack);
136 while(dstTrack != dstTrackRange.end())
138 if((*dstTrack)->GetSelected() && *lastCopiedTrack)
139 f(**lastCopiedTrack);
147 wxULongLong result{};
150 for(
auto& clip : waveTrack.
GetClips())
151 samplesCount += clip->GetSequenceSamplesCount();
159 BlockArray::size_type result{};
161 for(
auto& clip : waveTrack.
GetClips())
162 result += clip->GetSequenceBlockArray()->
size();
169 for(
auto track : src)
171 auto trackCopy = track->Copy(track->GetStartTime(), track->GetEndTime(),
false);
172 trackCopy->Init(*track);
173 trackCopy->SetOffset(track->GetStartTime());
175 if(
auto waveTrack =
dynamic_cast<WaveTrack*
>(trackCopy.get()))
177 for(
auto clip : waveTrack->GetClips())
179 if(clip->GetTrimLeft() != 0)
181 auto t0 = clip->GetPlayStartTime();
182 clip->SetTrimLeft(0);
185 if(clip->GetTrimRight() != 0)
187 auto t1 = clip->GetPlayEndTime();
188 clip->SetTrimRight(0);
189 clip->ClearRight(t1);
193 result->Add(trackCopy);
209 assert(!tracks.Selected());
211 Track* pFirstNewTrack = NULL;
212 for (
auto pClip : src) {
213 auto pNewTrack = pClip->
PasteInto( project );
214 bool newTrack = (pNewTrack.use_count() == 1);
218 pFirstNewTrack = pNewTrack.get();
233 selectedRegion.setTimes(
241 if (pFirstNewTrack) {
251 for(
auto& clip : waveTrack->GetClips())
253 if(clip->GetTrimLeft() != 0 || clip->GetTrimRight() != 0)
268 auto &project = context.
project;
280 if (trackPanel.IsMouseCaptured()) {
288 auto t = *tracks.Selected().begin();
290 t = *tracks.Any().begin();
299 auto &project = context.
project;
310 if (trackPanel.IsMouseCaptured()) {
318 auto t = *tracks.Selected().begin();
320 t = *tracks.Any().begin();
329 auto &project = context.
project;
340 for (
auto lt : tracks.Selected<
LabelTrack >()) {
342 if (view.CutSelectedText( context.
project )) {
343 trackPanel.Refresh(
false);
350 for (
auto wt : tracks.Any<
WaveTrack>()) {
352 if (view.CutSelectedText(context.
project)) {
353 trackPanel.Refresh(
false);
362 auto &newClipboard = *pNewClipboard;
364 tracks.Selected().Visit(
368 auto dest = n->
Cut(selectedRegion.t0(),
369 selectedRegion.t1());
375 auto dest = n->
Copy(selectedRegion.t0(),
376 selectedRegion.t1());
384 std::move( newClipboard ),
387 project.shared_from_this()
402 if (
gPrefs->Read(
wxT(
"/GUI/EnableCutLines"), (long)0)) {
405 selectedRegion.t1());
412 n->
Clear(selectedRegion.t0(), selectedRegion.t1());
416 selectedRegion.collapseToT0();
423 ruler.DrawOverlays(
true );
428 auto &project = context.
project;
433 for (
auto n : tracks.Any()) {
434 if (!n->SupportsBasicEditing())
437 n->Clear(selectedRegion.t0(), selectedRegion.t1());
441 double seconds = selectedRegion.duration();
443 selectedRegion.collapseToT0();
446 XO(
"Deleted %.2f seconds at t=%.2f")
447 .
Format( seconds, selectedRegion.t0()),
454 auto &project = context.
project;
459 for (
auto lt : tracks.Selected<
LabelTrack >()) {
461 if (view.CopySelectedText( context.
project )) {
468 for (
auto wt : tracks.Any<
WaveTrack>()) {
470 if (view.CopySelectedText(context.
project)) {
479 auto &newClipboard = *pNewClipboard;
481 for (
auto n : tracks.Selected()) {
482 if (n->SupportsBasicEditing()) {
483 auto dest = n->Copy(selectedRegion.t0(),
484 selectedRegion.t1());
490 clipboard.Assign( std::move( newClipboard ),
491 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
494 trackPanel.Refresh(
false);
499 double sel0 = 0.0, sel1 = 0.0;
504 auto &selectedRegion = *pRegion;
505 sel0 = selectedRegion.t0();
506 sel1 = selectedRegion.t1();
512 sel0 = selectedRegion.
t0();
513 sel1 = selectedRegion.t1();
516 return { sel0, sel1 };
521 auto &project = context.
project;
525 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
536 for (
auto wt : tracks.Any<
WaveTrack>()) {
538 if (view.PasteText(context.
project)) {
539 trackPanel.Refresh(
false);
545 if (clipboard.GetTracks().empty())
548 auto discardTrimmed =
false;
549 if(&context.
project != &*clipboard.Project().lock())
552 if(waveClipCopyPolicy ==
wxT(
"Ask") &&
HasHiddenData(clipboard.GetTracks())) {
557 const auto result = audioPasteDialog.ShowModal();
558 if(result == wxID_CANCEL)
563 else if(waveClipCopyPolicy ==
wxT(
"Discard"))
564 discardTrimmed =
true;
567 std::shared_ptr<const TrackList> srcTracks;
571 srcTracks = clipboard.GetTracks().shared_from_this();
573 auto scopedSubscription = pSampleBlockFactory->Subscribe([
576 copyStartTime = std::chrono::system_clock::now(),
577 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
579 using namespace std::chrono;
580 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
582 if(!progressDialog) {
583 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
587 progressDialog->Poll(nCopied, toCopy);
592 if(!tracks.Selected())
602 auto pN = tracks.Any().begin();
605 const Track *lastClipBeforeMismatch = NULL;
606 const Track *mismatchedClip = NULL;
607 const Track *prevClip = NULL;
609 bool bAdvanceClipboard =
true;
610 bool bPastedSomething =
false;
613 bPastedSomething =
true;
619 auto clipTrackRange = srcTracks->Any();
620 auto pC = clipTrackRange.begin();
621 size_t nnChannels=0, ncChannels=0;
625 if (n->GetSelected()) {
626 bAdvanceClipboard =
true;
629 if (!c->SameKindAs(*n)) {
630 if (!mismatchedClip) {
631 lastClipBeforeMismatch = prevClip;
634 bAdvanceClipboard =
false;
635 c = lastClipBeforeMismatch;
639 while (c && !c->SameKindAs(*n)) {
649 while (n && (!c->SameKindAs(*n) || !n->GetSelected()))
653 auto newT1 = t0 + clipboard.Duration();
654 if (t1 != newT1 && t1 <= n->GetEndTime()) {
656 bPastedSomething =
true;
673 XO(
"Pasting one type of track into another is not allowed."),
675 "Error:_Copying_or_Pasting"
680 if ( n->IsLeader() ) {
681 wxASSERT( c->IsLeader() );
690 if (ncChannels > nnChannels)
692 if (ncChannels > 2) {
702 XO(
"Copying stereo audio into a mono track is not allowed."),
704 "Error:_Copying_or_Pasting"
712 wxASSERT( n && c && n->SameKindAs(*c) );
715 pasteWaveTrack(wn,
static_cast<const WaveTrack *
>(c));
722 ln->ShiftLabelsOnInsert( clipboard.Duration(), t0 );
724 bPastedSomething |= ln->PasteOver(t0, c);
727 bPastedSomething =
true;
740 while (nnChannels > 0 && ncChannels == 0)
747 pasteWaveTrack(wn, c);
751 bPastedSomething =
true;
757 if (bAdvanceClipboard) {
764 auto newT1 = t0 + clipboard.Duration();
765 if (t1 != newT1 && t1 <= n->GetEndTime()) {
767 bPastedSomething =
true;
780 *srcTracks->Any<
const WaveTrack >().rbegin();
782 tracks.Any().StartingWith(*pN).Visit(
784 if (!wt->GetSelected())
785 return fallthrough();
788 pasteWaveTrack(wt, wc);
791 auto tmp = wt->EmptyCopy( pSampleBlockFactory );
792 tmp->InsertSilence( 0.0,
794 clipboard.Duration() );
797 pasteWaveTrack(wt, tmp.get());
802 return fallthrough();
809 clipboard.Duration(), t0);
813 n->SyncLockAdjust(t1, t0 + clipboard.Duration() );
820 if (bPastedSomething)
823 .
setTimes( t0, t0 + clipboard.Duration() );
831 ff->LinkConsistencyFix();
838 auto &project = context.
project;
844 auto range = tracks.Selected();
845 auto last = *range.rbegin();
846 for (
auto n : range) {
847 if (!n->SupportsBasicEditing())
851 auto dest = n->Copy(selectedRegion.t0(),
852 selectedRegion.t1(),
false);
854 dest->SetOffset(wxMax(selectedRegion.t0(), n->GetOffset()));
868 auto &project = context.
project;
877 auto &newClipboard = *pNewClipboard;
881 tracks.Selected().Visit(
885 selectedRegion.t1());
891 dest = n->
Copy(selectedRegion.t0(),
892 selectedRegion.t1());
893 n->
Silence(selectedRegion.t0(),
894 selectedRegion.t1());
902 clipboard.Assign( std::move( newClipboard ),
903 selectedRegion.t0(), selectedRegion.t1(), project.shared_from_this() );
906 .
PushState(
XO(
"Split-cut to the clipboard"),
XO(
"Split Cut"));
911 auto &project = context.
project;
916 tracks.Selected().Visit(
919 selectedRegion.t1());
922 if (n->SupportsBasicEditing())
923 n->Silence(selectedRegion.t0(),
924 selectedRegion.t1());
929 XO(
"Split-deleted %.2f seconds at t=%.2f")
930 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
936 auto &project = context.
project;
940 for (
auto n : tracks.Selected<
WaveTrack >() )
941 n->Silence(selectedRegion.t0(), selectedRegion.t1());
944 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
945 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
947 XC(
"Silence",
"command"));
952 auto &project = context.
project;
957 if (selectedRegion.isPoint())
960 tracks.Selected().Visit(
963 wt->
Trim(selectedRegion.t0(),
964 selectedRegion.t1());
969 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
970 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
976 auto &project = context.
project;
982 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
984 pChannel->Split( sel0, sel1 );
990 for (
auto wt : tracks.Selected<
WaveTrack >())
991 wt->Split( sel0, sel1 );
1045 auto &project = context.
project;
1053 auto range = tracks.Selected();
1054 auto last = *range.rbegin();
1055 for (
auto track : range) {
1061 selectedRegion.t0()));
1063 selectedRegion.t1()));
1066 dest = wt->
Copy(newt0, newt1,
false);
1071 dest->Offset(newt0);
1080 dest = n->Cut(viewInfo.selectedRegion.t0(),
1081 viewInfo.selectedRegion.t1());
1083 dest->SetOffset(wxMax(0, n->GetOffset()));
1099 auto &project = context.
project;
1104 for (
auto wt : tracks.Selected<
WaveTrack >())
1105 wt->Join(selectedRegion.t0(),
1106 selectedRegion.t1());
1109 XO(
"Joined %.2f seconds at t=%.2f")
1110 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
1116 auto &project = context.
project;
1121 for (
auto wt : tracks.Selected<
WaveTrack >())
1122 wt->Disjoin(selectedRegion.t0(),
1123 selectedRegion.t1());
1126 XO(
"Detached %.2f seconds at t=%.2f")
1127 .
Format( selectedRegion.duration(), selectedRegion.t0() ),
1133 auto &project = context.
project;
1151#if defined(__WXGTK__)
1159 wxRect r = window.GetRect();
1160 window.SetSize(wxSize(1,1));
1161 window.SetSize(r.GetSize());
1171 auto &project = context.
project;
1172 auto &selectedRegion = project.GetViewInfo().selectedRegion;
1174 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
1176 selectedRegion.setT1(
1177 selectedRegion.t0() +
1178 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1199 if ( !range.empty() )
1219 static const auto NotBusyTimeAndTracksFlags =
1223 static constexpr auto redoKey =
1233 static constexpr auto prefKey =
1274 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+D") ),
1277 Menu(
wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1281 NotBusyTimeAndTracksFlags,
1285 NotBusyTimeAndTracksFlags,
1321 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+J") ),
1323 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+Alt+J") )
1350 static const auto flags =
1403 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)
Toolkit-neutral facade for basic user interface services.
AttachedItem sAttachment1
AttachedItem sAttachment2
std::bitset< NCommandFlags > CommandFlag
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)
XXO("&Cut/Copy/Paste Toolbar")
#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,...
ChoiceSetting TracksBehaviorsAudioTrackPastePolicy
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 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 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)
bool IsSyncLocked() const
static SyncLockState & Get(AudacityProject &project)
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)
static size_t NChannels(const Track &track)
Count channels of a track.
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
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)
sampleFormat GetSampleFormat() const override
void Silence(double t0, double t1) override
void ClearAndAddCutLine(double t0, double t1)
void Trim(double t0, double t1)
WaveClipHolders & GetClips()
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)
Positions or offsets within audio files need a wide type.
long long as_long_long() const
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
void Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItemBase *pRegistry)
std::unique_ptr< IndirectItem > Indirect(const BaseItemSharedPtr &ptr)
A convenience function.
std::shared_ptr< BaseItem > BaseItemSharedPtr
void DoSelectAllAudio(AudacityProject &project)
CommandManager::Options Options
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.