1#include "../AdornedRulerPanel.h"
2#include "../Clipboard.h"
3#include "../CommonCommandFlags.h"
4#include "../LabelTrack.h"
5#include "../MenuCreator.h"
11#include "../ProjectWindows.h"
12#include "../ProjectWindows.h"
13#include "../SelectUtilities.h"
15#include "../TrackPanel.h"
25#include "../prefs/PrefsDialog.h"
26#include "../prefs/TracksBehaviorsPrefs.h"
27#include "../tracks/labeltrack/ui/LabelTrackView.h"
28#include "../tracks/playabletrack/wavetrack/ui/WaveChannelView.h"
30#include "../AudioPasteDialog.h"
56 if (view.PasteSelectedText(
project, selectedRegion.t0(),
57 selectedRegion.t1() ))
60 .
PushState(
XO(
"Pasted text from the clipboard"),
XO(
"Paste"));
64 if (view.CalcCursorX(
project, &x )) {
65 viewport.ScrollIntoView(x);
79 trackPanel.Refresh(
false);
91 const auto samplesCount = waveTrack->GetSequenceSamplesCount();
92 result += samplesCount.as_long_long() *
100 BlockArray::size_type result{};
102 result += waveTrack->CountBlocks();
108 for (
auto track : src) {
110 track->Copy(track->GetStartTime(), track->GetEndTime(),
false);
111 const auto pTrack = *copies->begin();
112 pTrack->MoveTo(track->GetStartTime());
113 if (
const auto waveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
114 waveTrack->DiscardTrimmed();
115 result->Append(std::move(*copies));
130 assert(
tracks.Selected().empty());
132 Track* pFirstNewTrack = NULL;
133 for (
auto pClip : src) {
136 pFirstNewTrack = pNewTrack.get();
145 const double srcTempo =
146 pFirstNewTrack ? pFirstNewTrack->
GetProjectTempo().value_or(projTempo) :
151 const double quantT0 =
QUANTIZED_TIME(t0 * srcTempo / projTempo, projRate);
152 const double quantT1 =
QUANTIZED_TIME(t1 * srcTempo / projTempo, projRate);
153 selectedRegion.setTimes(
161 if (pFirstNewTrack) {
170 return std::any_of(range.begin(), range.end(),
171 [](
const WaveTrack *pTrack){ return pTrack->HasHiddenData(); });
189 if (trackPanel.IsMouseCaptured()) {
197 auto t = *
tracks.Selected().begin();
217 if (trackPanel.IsMouseCaptured()) {
225 auto t = *
tracks.Selected().begin();
247 if (view.CutSelectedText( context.
project )) {
248 trackPanel.Refresh(
false);
257 if (view.CutSelectedText(context.
project)) {
258 trackPanel.Refresh(
false);
267 auto &newClipboard = *pNewClipboard;
273 auto dest = n.
Cut(selectedRegion.t0(), selectedRegion.t1());
274 newClipboard.Append(std::move(*dest));
279 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
280 newClipboard.Append(std::move(*dest));
287 std::move( newClipboard ),
304 [&](
auto &&fallthrough){
return [&](
WaveTrack &wt) {
306 wt.ClearAndAddCutLine(selectedRegion.t0(), selectedRegion.t1());
312 n.
Clear(selectedRegion.t0(), selectedRegion.t1());
316 selectedRegion.collapseToT0();
323 ruler.DrawOverlays(
true );
333 if (!n->SupportsBasicEditing())
336 n->Clear(selectedRegion.t0(), selectedRegion.t1());
340 double seconds = selectedRegion.
duration();
342 selectedRegion.collapseToT0();
345 XO(
"Deleted %.2f seconds at t=%.2f")
346 .
Format( seconds, selectedRegion.t0()),
360 if (view.CopySelectedText( context.
project )) {
369 if (view.CopySelectedText(context.
project)) {
378 auto &newClipboard = *pNewClipboard;
380 for (
auto n :
tracks.Selected()) {
381 if (n->SupportsBasicEditing()) {
382 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1());
383 newClipboard.Append(std::move(*dest));
388 clipboard.Assign( std::move( newClipboard ),
389 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this() );
392 trackPanel.Refresh(
false);
397 double sel0 = 0.0, sel1 = 0.0;
402 auto &selectedRegion = *pRegion;
403 sel0 = selectedRegion.t0();
404 sel1 = selectedRegion.t1();
410 sel0 = selectedRegion.
t0();
411 sel1 = selectedRegion.t1();
414 return { sel0, sel1 };
423 auto discardTrimmed =
false;
424 if (&context.
project != &*clipboard.Project().lock()) {
426 if(waveClipCopyPolicy ==
wxT(
"Ask") &&
HasHiddenData(clipboard.GetTracks())) {
431 const auto result = audioPasteDialog.ShowModal();
432 if(result == wxID_CANCEL)
437 else if(waveClipCopyPolicy ==
wxT(
"Discard"))
438 discardTrimmed =
true;
441 std::shared_ptr<const TrackList> srcTracks;
445 srcTracks = clipboard.GetTracks().shared_from_this();
456 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
457 return pSampleBlockFactory->Subscribe([
460 copyStartTime = std::chrono::system_clock::now(),
461 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
463 using namespace std::chrono;
464 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
466 if(!progressDialog) {
467 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
471 progressDialog->Poll(nCopied, toCopy);
494 auto dstRange = dstTracks.
Selected();
495 if (dstRange.size() == 1)
498 dstRange = dstTracks.
Any().StartingWith(*dstRange.begin());
499 auto srcRange = srcTracks.
Any();
500 while (!(dstRange.empty() || srcRange.empty())) {
501 auto &dst = **dstRange.begin();
502 auto &src = **srcRange.begin();
508 result.emplace_back(&dst, &src);
513 if (!srcRange.empty())
529 if (clipboard.GetTracks().empty())
543 project, *srcTracks, clipboard.T0(), clipboard.T1());
550 auto newT1 = t0 + clipboard.Duration();
554 bool bPastedSomething =
false;
558 if (correspondence.empty()) {
559 if (
tracks.Selected().size() == 1)
561"The content you are trying to paste will span across more tracks than you "
562"currently have available. Add more tracks and try again.")
566"There are not enough tracks selected to accommodate your copied content. "
567"Select additional tracks and try again.")
571 auto iPair = correspondence.begin();
572 const auto endPair = correspondence.cend();
575 auto next =
tracks.begin();
576 for (
auto range =
tracks.Any(); !range.empty();
580 if (iPair == endPair)
584 next =
tracks.Find(*group.rbegin());
587 if (!group.contains(iPair->first))
592 for (
auto leader : group) {
593 if (iPair == endPair || leader != iPair->first) {
596 if (t1 != newT1 && t1 <= leader->GetEndTime()) {
597 leader->SyncLockAdjust(t1, newT1);
598 bPastedSomething =
true;
607 const auto src = (iPair++)->second;
610 bPastedSomething =
true;
613 const auto newClipOnPaste =
621 const auto merge = newClipOnPaste ? false :
true;
622 const auto preserveExistingBoundaries = newClipOnPaste ? false :
true;
623 auto clearByTrimming = newClipOnPaste ? true :
false;
625 t0, t1, *
static_cast<const WaveTrack*
>(src),
626 preserveExistingBoundaries, merge, &warper,
634 ln.ShiftLabelsOnInsert( clipboard.Duration(), t0 );
636 bPastedSomething |= ln.PasteOver(t0, *src);
639 bPastedSomething =
true;
650 if (bPastedSomething) {
652 .
setTimes( t0, t0 + clipboard.Duration() );
671 auto range =
tracks.Selected();
672 auto last = *range.rbegin();
673 for (
auto n : range) {
674 if (!n->SupportsBasicEditing())
678 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1(),
false);
680 ->MoveTo(std::max(selectedRegion.t0(), n->GetStartTime()));
681 tracks.Append(std::move(*dest));
702 auto &newClipboard = *pNewClipboard;
706 auto tracks = n.
SplitCut(selectedRegion.t0(), selectedRegion.t1());
707 newClipboard.Append(std::move(*
tracks));
711 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
712 n.
Silence(selectedRegion.t0(), selectedRegion.t1());
713 newClipboard.Append(std::move(*dest));
719 clipboard.Assign(std::move(newClipboard),
720 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this());
723 .
PushState(
XO(
"Split-cut to the clipboard"),
XO(
"Split Cut"));
734 wt.
SplitDelete(selectedRegion.t0(), selectedRegion.t1());
737 if (n.SupportsBasicEditing())
738 n.Silence(selectedRegion.t0(), selectedRegion.t1());
743 XO(
"Split-deleted %.2f seconds at t=%.2f")
744 .
Format(selectedRegion.duration(), selectedRegion.t0()),
758 selectedWaveTracks.begin(), selectedWaveTracks.end(),
760 n->Silence(selectedRegion.t0(), selectedRegion.t1(), child);
766 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
767 .
Format(selectedRegion.duration(), selectedRegion.t0()),
769 XC(
"Silence",
"command"));
778 if (selectedRegion.isPoint())
783 wt.
Trim(selectedRegion.t0(), selectedRegion.t1());
787 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
788 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
798 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
799 pWaveTrack->Split(sel0, sel1);
806 wt->Split(sel0, sel1);
864 auto range =
tracks.Selected();
865 auto last = *range.rbegin();
866 for (
auto track : range) {
871 const double newt0 = wt.
SnapToSample(selectedRegion.t0());
872 const double newt1 = wt.
SnapToSample(selectedRegion.t1());
875 const auto dest = wt.
Copy(newt0, newt1,
false);
879 (*dest->begin())->MoveTo(newt0);
880 tracks.Append(std::move(*dest));
889 dest = n.Cut(viewInfo.selectedRegion.t0(),
890 viewInfo.selectedRegion.t1());
892 dest->MoveTo(std::max(0, n.GetOffset()));
916 selectedTracks.begin(), selectedTracks.end(),
919 selectedRegion.t0(), selectedRegion.t1(), childProgress);
925 XO(
"Joined %.2f seconds at t=%.2f")
926 .
Format(selectedRegion.duration(), selectedRegion.t0()),
937 wt->Disjoin(selectedRegion.t0(), selectedRegion.t1());
940 XO(
"Detached %.2f seconds at t=%.2f")
941 .
Format(selectedRegion.duration(), selectedRegion.t0()),
962#if defined(__WXGTK__)
970 wxRect r = window.GetRect();
971 window.SetSize(wxSize(1,1));
972 window.SetSize(r.GetSize());
983 auto &selectedRegion =
project.GetViewInfo().selectedRegion;
985 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
987 selectedRegion.setT1(
988 selectedRegion.t0() +
989 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1010 if ( !range.empty() )
1033 if(viewInfo.selectedRegion.isPoint())
1037 for(
const auto track : selectedTracks)
1039 const auto selectedClips =
1041 if(selectedClips.size() > 1)
1052 static const auto NotBusyTimeAndTracksFlags =
1056 static constexpr auto redoKey =
1066 static constexpr auto prefKey =
1074 static auto menu = std::shared_ptr{
1107 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+D") ),
1110 Menu(
wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1114 NotBusyTimeAndTracksFlags,
1118 NotBusyTimeAndTracksFlags,
1156 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+Alt+J") )
1179 static const auto flags =
1181 static auto menu = std::shared_ptr{
1232 wxT(
"Optional/Extra/Part1")
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()
bool AudioIOBusyPred(const AudacityProject &project)
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & EditableTracksSelectedFlag()
const ReservedCommandFlag & AnyTracksSelectedFlag()
const ReservedCommandFlag & TracksExistFlag()
const ReservedCommandFlag & WaveTracksExistFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
bool TimeSelectedPred(const AudacityProject &project)
XXO("&Cut/Copy/Paste Toolbar")
#define QUANTIZED_TIME(time, rate)
audacity::BasicSettings * gPrefs
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,...
std::function< void(double)> ProgressReporter
ChoiceSetting TracksBehaviorsAudioTrackPastePolicy
An AudacityException with no visible message.
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 CommandManager & Get(AudacityProject &project)
void ModifyUndoMenuItems()
A LabelTrack is a Track that holds labels (LabelStruct).
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).
TrackListHolder Cut(double t0, double t1) override
Create tracks and modify this track.
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
void Clear(double t0, double t1) 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 ProjectTimeSignature & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
static TrackIterRange< Track > Group(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.
virtual void SetSelected(bool s)
virtual Holder PasteInto(AudacityProject &project, TrackList &list) const =0
bool SameKindAs(const Track &track) const
virtual bool SupportsBasicEditing() const
Whether this track type implements cut-copy-paste; by default, true.
R TypeSwitch(const Functions &...functions)
const std::optional< double > & GetProjectTempo() const
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
static TrackListHolder Create(AudacityProject *pOwner)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
auto Selected() -> TrackIterRange< TrackType >
static TrackPanel & Get(AudacityProject &project)
static UndoManager & Get(AudacityProject &project)
NotifyingSelectedRegion selectedRegion
static ViewInfo & Get(AudacityProject &project)
void ShowTrack(const Track &track)
static Viewport & Get(AudacityProject &project)
static WaveChannelView & Get(WaveChannel &channel)
static WaveTrackFactory & Get(AudacityProject &project)
A Track that contains audio waveform data.
void SplitDelete(double t0, double t1)
void Silence(double t0, double t1, ProgressReporter reportProgress) override
WaveClipConstHolders GetClipsIntersecting(double t0, double t1) const
void Trim(double t0, double t1)
TrackListHolder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
TrackListHolder SplitCut(double t0, double t1)
double SnapToSample(double t) const
bool ReadBool(const wxString &key, bool defaultValue) const
virtual bool Read(const wxString &key, bool *value) const =0
std::function< void(double)> ProgressReporter
void SplitProgress(ItType first, ItType last, FnType action, ProgressReporter parent)
Helper for the update of a task's progress bar when this task is made of a range's subtasks.
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
void DoSelectAllAudio(AudacityProject &project)
WAVE_TRACK_API void WithClipRenderingProgress(std::function< void(const ProgressReporter &)> action, TranslatableString title=defaultStretchRenderingTitle, TranslatableString message=XO("Rendering Clip"))
CommandFlagOptions && DisableDefaultMessage() &&
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.