1#include "../AdornedRulerPanel.h"
2#include "../Clipboard.h"
3#include "../CommonCommandFlags.h"
5#include "../MenuCreator.h"
12#include "../ProjectWindows.h"
13#include "../ProjectWindows.h"
14#include "../SelectUtilities.h"
17#include "../TrackPanel.h"
28#include "../prefs/PrefsDialog.h"
29#include "../prefs/TracksBehaviorsPrefs.h"
30#include "../tracks/labeltrack/ui/LabelTrackView.h"
31#include "../tracks/playabletrack/wavetrack/ui/WaveChannelView.h"
33#include "../AudioPasteDialog.h"
39#include <wx/clipbrd.h>
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 viewport.ScrollIntoView(x);
83 trackPanel.Refresh(
false);
95 const auto samplesCount =
97 result += samplesCount.as_long_long() *
105 BlockArray::size_type result{};
113 for (
auto track : src) {
115 track->Copy(track->GetStartTime(), track->GetEndTime(),
false);
116 pTrack->MoveTo(track->GetStartTime());
117 if (
const auto waveTrack =
dynamic_cast<WaveTrack*
>(pTrack.get()))
134 assert(
tracks.Selected().empty());
136 Track* pFirstNewTrack = NULL;
137 for (
auto pClip : src) {
140 pFirstNewTrack = pNewTrack.get();
149 const double srcTempo =
150 pFirstNewTrack ?
GetProjectTempo(*pFirstNewTrack).value_or(projTempo) :
155 const double quantT0 =
QUANTIZED_TIME(t0 * srcTempo / projTempo, projRate);
156 const double quantT1 =
QUANTIZED_TIME(t1 * srcTempo / projTempo, projRate);
157 selectedRegion.setTimes(
165 if (pFirstNewTrack) {
174 return std::any_of(range.begin(), range.end(),
176 return WaveTrackUtilities::HasHiddenData(*pTrack);
195 if (trackPanel.IsMouseCaptured()) {
203 auto t = *
tracks.Selected().begin();
223 if (trackPanel.IsMouseCaptured()) {
231 auto t = *
tracks.Selected().begin();
241 if (wxTheClipboard->Open())
246 const auto success = wxTheClipboard->SetData(
safenew wxTextDataObject);
248 wxTheClipboard->Clear();
249 wxTheClipboard->Close();
269 if (view.CutSelectedText( context.
project )) {
270 trackPanel.Refresh(
false);
279 if (view.CutSelectedText(context.
project)) {
280 trackPanel.Refresh(
false);
289 auto &newClipboard = *pNewClipboard;
295 auto dest = n.
Cut(selectedRegion.t0(), selectedRegion.t1());
296 newClipboard.Add(dest);
301 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
302 newClipboard.Add(dest);
309 std::move( newClipboard ),
326 [&](
auto &&fallthrough){
return [&](
WaveTrack &wt) {
328 wt.ClearAndAddCutLine(selectedRegion.t0(), selectedRegion.t1());
334 n.
Clear(selectedRegion.t0(), selectedRegion.t1());
338 selectedRegion.collapseToT0();
345 ruler.DrawOverlays(
true );
355 if (!n->SupportsBasicEditing())
358 n->Clear(selectedRegion.t0(), selectedRegion.t1());
362 double seconds = selectedRegion.
duration();
364 selectedRegion.collapseToT0();
367 XO(
"Deleted %.2f seconds at t=%.2f")
368 .
Format( seconds, selectedRegion.t0()),
384 if (view.CopySelectedText( context.
project )) {
393 if (view.CopySelectedText(context.
project)) {
402 auto &newClipboard = *pNewClipboard;
404 for (
auto n :
tracks.Selected()) {
405 if (n->SupportsBasicEditing()) {
406 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1());
407 newClipboard.Add(dest);
412 clipboard.Assign( std::move( newClipboard ),
413 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this() );
416 trackPanel.Refresh(
false);
421 double sel0 = 0.0, sel1 = 0.0;
426 auto &selectedRegion = *pRegion;
427 sel0 = selectedRegion.t0();
428 sel1 = selectedRegion.t1();
434 sel0 = selectedRegion.
t0();
435 sel1 = selectedRegion.t1();
438 return { sel0, sel1 };
447 auto discardTrimmed =
false;
448 if (&context.
project != &*clipboard.Project().lock()) {
450 if (waveClipCopyPolicy ==
wxT(
"Ask") &&
457 const auto result = audioPasteDialog.ShowModal();
458 if(result == wxID_CANCEL)
463 else if(waveClipCopyPolicy ==
wxT(
"Discard"))
464 discardTrimmed =
true;
467 std::shared_ptr<const TrackList> srcTracks;
471 srcTracks = clipboard.GetTracks().shared_from_this();
482 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
483 return pSampleBlockFactory->Subscribe([
486 copyStartTime = std::chrono::system_clock::now(),
487 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
489 using namespace std::chrono;
490 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
492 if(!progressDialog) {
493 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
497 progressDialog->Poll(nCopied, toCopy);
520 auto dstRange = dstTracks.
Selected();
521 if (dstRange.size() == 1)
524 dstRange = dstTracks.
Any().StartingWith(*dstRange.begin());
525 auto srcRange = srcTracks.
Any();
526 while (!(dstRange.empty() || srcRange.empty())) {
527 auto &dst = **dstRange.begin();
528 auto &src = **srcRange.begin();
534 result.emplace_back(&dst, &src);
539 if (!srcRange.empty())
548 if (wxTheClipboard->IsSupported(wxDF_FILENAME) && wxTheClipboard->Open())
550 wxFileDataObject data;
551 const auto hadData = wxTheClipboard->GetData(data);
552 wxTheClipboard->Close();
567 if (clipboard.GetTracks().empty())
581 project, *srcTracks, clipboard.T0(), clipboard.T1());
588 auto newT1 = t0 + clipboard.Duration();
592 bool bPastedSomething =
false;
596 if (correspondence.empty()) {
597 if (
tracks.Selected().size() == 1)
599"The content you are trying to paste will span across more tracks than you "
600"currently have available. Add more tracks and try again.")
604"There are not enough tracks selected to accommodate your copied content. "
605"Select additional tracks and try again.")
609 auto iPair = correspondence.begin();
610 const auto endPair = correspondence.cend();
613 auto next =
tracks.begin();
614 for (
auto range =
tracks.Any(); !range.empty();
618 if (iPair == endPair)
622 next =
tracks.Find(*group.rbegin());
625 if (!group.contains(iPair->first))
630 for (
auto member : group) {
631 if (iPair == endPair || member != iPair->first) {
634 if (t1 != newT1 && t1 <= member->GetEndTime()) {
635 member->SyncLockAdjust(t1, newT1);
636 bPastedSomething =
true;
645 const auto src = (iPair++)->second;
648 bPastedSomething =
true;
651 const auto newClipOnPaste =
659 const auto merge = newClipOnPaste ? false :
true;
660 const auto preserveExistingBoundaries = newClipOnPaste ? false :
true;
661 auto clearByTrimming = newClipOnPaste ? true :
false;
662 if(src->NChannels() == 1 && wn.
NChannels() == 2)
666 const auto pastedTrack = std::static_pointer_cast<WaveTrack>(src->Duplicate());
667 pastedTrack->MonoToStereo();
669 t0, t1, *pastedTrack,
670 preserveExistingBoundaries, merge, &warper,
676 t0, t1, *
static_cast<const WaveTrack*
>(src),
677 preserveExistingBoundaries, merge, &warper,
686 ln.ShiftLabelsOnInsert( clipboard.Duration(), t0 );
688 bPastedSomething |= ln.PasteOver(t0, *src);
691 bPastedSomething =
true;
702 if (bPastedSomething) {
710 const auto offset = srcTracks->GetEndTime() - (t1 - t0);
713 const auto it = std::find_if(correspondence.begin(), correspondence.end(),
714 [=](
auto& p) { return p.first == track; });
715 if(it != correspondence.end())
718 track->ShiftBy(t0, offset);
723 .
setTimes( t0, t0 + clipboard.Duration() );
742 auto range =
tracks.Selected();
743 auto last = *range.rbegin();
744 for (
auto n : range) {
745 if (!n->SupportsBasicEditing())
749 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1(),
false);
750 dest->MoveTo(std::max(selectedRegion.t0(), n->GetStartTime()));
772 auto &newClipboard = *pNewClipboard;
776 auto track = n.
SplitCut(selectedRegion.t0(), selectedRegion.t1());
777 newClipboard.Add(track);
781 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
782 n.
Silence(selectedRegion.t0(), selectedRegion.t1());
783 newClipboard.Add(dest);
789 clipboard.Assign(std::move(newClipboard),
790 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this());
793 .
PushState(
XO(
"Cut to clipboard and leave gap"),
XO(
"Cut and leave gap"));
804 wt.
SplitDelete(selectedRegion.t0(), selectedRegion.t1());
807 if (n.SupportsBasicEditing())
808 n.Silence(selectedRegion.t0(), selectedRegion.t1());
813 XO(
"Split-deleted %.2f seconds at t=%.2f")
814 .
Format(selectedRegion.duration(), selectedRegion.t0()),
828 selectedWaveTracks.begin(), selectedWaveTracks.end(),
830 n->Silence(selectedRegion.t0(), selectedRegion.t1(), child);
836 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
837 .
Format(selectedRegion.duration(), selectedRegion.t0()),
839 XC(
"Silence",
"command"));
848 if (selectedRegion.isPoint())
853 wt.
Trim(selectedRegion.t0(), selectedRegion.t1());
857 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
858 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
868 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
869 pWaveTrack->Split(sel0, sel1);
876 wt->Split(sel0, sel1);
934 auto range =
tracks.Selected();
935 auto last = *range.rbegin();
936 for (
auto track : range) {
941 const double newt0 = wt.
SnapToSample(selectedRegion.t0());
942 const double newt1 = wt.
SnapToSample(selectedRegion.t1());
945 const auto dest = wt.
Copy(newt0, newt1,
false);
959 dest = n.Cut(viewInfo.selectedRegion.t0(),
960 viewInfo.selectedRegion.t1());
962 dest->MoveTo(std::max(0, n.GetOffset()));
986 selectedTracks.begin(), selectedTracks.end(),
989 selectedRegion.t0(), selectedRegion.t1(), childProgress);
995 XO(
"Joined %.2f seconds at t=%.2f")
996 .
Format(selectedRegion.duration(), selectedRegion.t0()),
1007 wt->Disjoin(selectedRegion.t0(), selectedRegion.t1());
1010 XO(
"Detached %.2f seconds at t=%.2f")
1011 .
Format(selectedRegion.duration(), selectedRegion.t0()),
1032#if defined(__WXGTK__)
1040 wxRect r = window.GetRect();
1041 window.SetSize(wxSize(1,1));
1042 window.SetSize(r.GetSize());
1053 auto &selectedRegion =
project.GetViewInfo().selectedRegion;
1055 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
1057 selectedRegion.setT1(
1058 selectedRegion.t0() +
1059 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1080 if ( !range.empty() )
1103 if(viewInfo.selectedRegion.isPoint())
1107 for (
const auto track : selectedTracks)
1109 const auto selectedClips =
1111 viewInfo.selectedRegion.t0(), viewInfo.selectedRegion.t1());
1112 if(selectedClips.size() > 1)
1123 static const auto NotBusyTimeAndTracksFlags =
1127 static constexpr auto redoKey =
1137 static constexpr auto prefKey =
1145 static auto menu = std::shared_ptr{
1178 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+D") ),
1181 Menu(
wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1185 NotBusyTimeAndTracksFlags,
1189 NotBusyTimeAndTracksFlags,
1227 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+Alt+J") )
1250 static const auto flags =
1252 static auto menu = std::shared_ptr{
1303 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 ...
const std::optional< double > & GetProjectTempo(const ChannelGroup &group)
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper,...
std::function< void(double)> ProgressReporter
ChoiceSetting TracksBehaviorsAudioTrackPastePolicy
An AudacityException with no visible message.
bool GetEditClipsCanMove()
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...
virtual size_t NChannels() const =0
Report the number of channels.
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).
Track::Holder Cut(double t0, double t1) override
Create tracks and modify this track.
void Clear(double t0, double t1) override
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
bool setTimes(double t0, double t1)
Unit slope but with either a jump (pasting more) or a flat interval (pasting less)
bool Import(const FilePath &fileName, bool addToHistory=true)
static ProjectFileManager & Get(AudacityProject &project)
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 TrackIterRange< Track > Group(Track &track)
static bool IsSelectedOrSyncLockSelectedP(const Track *pTrack)
static bool IsSelectedOrSyncLockSelected(const Track &track)
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)
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 & GetFirst(WaveTrack &wt)
Get the view of the first 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
void Trim(double t0, double t1)
Holder SplitCut(double t0, double t1)
size_t NChannels() const override
A constant property.
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
Track::Holder Copy(double t0, double t1, bool forClipboard=true) const override
Create new tracks and don't modify this track.
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)
WAVE_TRACK_API size_t CountBlocks(const WaveTrack &track)
WAVE_TRACK_API sampleCount GetSequenceSamplesCount(const WaveTrack &track)
WAVE_TRACK_API void DiscardTrimmed(WaveTrack &track)
Remove hidden audio from all clips.
WAVE_TRACK_API WaveTrack::IntervalConstHolders GetClipsIntersecting(const WaveTrack &track, double t0, double t1)
CommandFlagOptions && DisableDefaultMessage() &&
SelectedRegion * pSelectedRegion
Holds one item with description and time range for the UndoManager.