1#include "../AdornedRulerPanel.h"
2#include "../Clipboard.h"
3#include "../CommonCommandFlags.h"
4#include "../LabelTrack.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();
253 if (view.CutSelectedText( context.
project )) {
254 trackPanel.Refresh(
false);
263 if (view.CutSelectedText(context.
project)) {
264 trackPanel.Refresh(
false);
273 auto &newClipboard = *pNewClipboard;
279 auto dest = n.
Cut(selectedRegion.t0(), selectedRegion.t1());
280 newClipboard.Add(dest);
285 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
286 newClipboard.Add(dest);
293 std::move( newClipboard ),
310 [&](
auto &&fallthrough){
return [&](
WaveTrack &wt) {
312 wt.ClearAndAddCutLine(selectedRegion.t0(), selectedRegion.t1());
318 n.
Clear(selectedRegion.t0(), selectedRegion.t1());
322 selectedRegion.collapseToT0();
329 ruler.DrawOverlays(
true );
339 if (!n->SupportsBasicEditing())
342 n->Clear(selectedRegion.t0(), selectedRegion.t1());
346 double seconds = selectedRegion.
duration();
348 selectedRegion.collapseToT0();
351 XO(
"Deleted %.2f seconds at t=%.2f")
352 .
Format( seconds, selectedRegion.t0()),
359 if (wxTheClipboard->Open())
364 const auto success = wxTheClipboard->SetData(
safenew wxTextDataObject);
366 wxTheClipboard->Clear();
367 wxTheClipboard->Close();
377 if (view.CopySelectedText( context.
project )) {
386 if (view.CopySelectedText(context.
project)) {
395 auto &newClipboard = *pNewClipboard;
397 for (
auto n :
tracks.Selected()) {
398 if (n->SupportsBasicEditing()) {
399 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1());
400 newClipboard.Add(dest);
405 clipboard.Assign( std::move( newClipboard ),
406 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this() );
409 trackPanel.Refresh(
false);
414 double sel0 = 0.0, sel1 = 0.0;
419 auto &selectedRegion = *pRegion;
420 sel0 = selectedRegion.t0();
421 sel1 = selectedRegion.t1();
427 sel0 = selectedRegion.
t0();
428 sel1 = selectedRegion.t1();
431 return { sel0, sel1 };
440 auto discardTrimmed =
false;
441 if (&context.
project != &*clipboard.Project().lock()) {
443 if (waveClipCopyPolicy ==
wxT(
"Ask") &&
450 const auto result = audioPasteDialog.ShowModal();
451 if(result == wxID_CANCEL)
456 else if(waveClipCopyPolicy ==
wxT(
"Discard"))
457 discardTrimmed =
true;
460 std::shared_ptr<const TrackList> srcTracks;
464 srcTracks = clipboard.GetTracks().shared_from_this();
475 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
476 return pSampleBlockFactory->Subscribe([
479 copyStartTime = std::chrono::system_clock::now(),
480 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
482 using namespace std::chrono;
483 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
485 if(!progressDialog) {
486 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
490 progressDialog->Poll(nCopied, toCopy);
513 auto dstRange = dstTracks.
Selected();
514 if (dstRange.size() == 1)
517 dstRange = dstTracks.
Any().StartingWith(*dstRange.begin());
518 auto srcRange = srcTracks.
Any();
519 while (!(dstRange.empty() || srcRange.empty())) {
520 auto &dst = **dstRange.begin();
521 auto &src = **srcRange.begin();
527 result.emplace_back(&dst, &src);
532 if (!srcRange.empty())
541 if (wxTheClipboard->IsSupported(wxDF_FILENAME) && wxTheClipboard->Open())
543 wxFileDataObject data;
544 const auto hadData = wxTheClipboard->GetData(data);
545 wxTheClipboard->Close();
560 if (clipboard.GetTracks().empty())
574 project, *srcTracks, clipboard.T0(), clipboard.T1());
581 auto newT1 = t0 + clipboard.Duration();
585 bool bPastedSomething =
false;
589 if (correspondence.empty()) {
590 if (
tracks.Selected().size() == 1)
592"The content you are trying to paste will span across more tracks than you "
593"currently have available. Add more tracks and try again.")
597"There are not enough tracks selected to accommodate your copied content. "
598"Select additional tracks and try again.")
602 auto iPair = correspondence.begin();
603 const auto endPair = correspondence.cend();
606 auto next =
tracks.begin();
607 for (
auto range =
tracks.Any(); !range.empty();
611 if (iPair == endPair)
615 next =
tracks.Find(*group.rbegin());
618 if (!group.contains(iPair->first))
623 for (
auto member : group) {
624 if (iPair == endPair || member != iPair->first) {
627 if (t1 != newT1 && t1 <= member->GetEndTime()) {
628 member->SyncLockAdjust(t1, newT1);
629 bPastedSomething =
true;
638 const auto src = (iPair++)->second;
641 bPastedSomething =
true;
644 const auto newClipOnPaste =
652 const auto merge = newClipOnPaste ? false :
true;
653 const auto preserveExistingBoundaries = newClipOnPaste ? false :
true;
654 auto clearByTrimming = newClipOnPaste ? true :
false;
655 if(src->NChannels() == 1 && wn.
NChannels() == 2)
659 const auto pastedTrack = std::static_pointer_cast<WaveTrack>(src->Duplicate());
660 pastedTrack->MonoToStereo();
662 t0, t1, *pastedTrack,
663 preserveExistingBoundaries, merge, &warper,
669 t0, t1, *
static_cast<const WaveTrack*
>(src),
670 preserveExistingBoundaries, merge, &warper,
679 ln.ShiftLabelsOnInsert( clipboard.Duration(), t0 );
681 bPastedSomething |= ln.PasteOver(t0, *src);
684 bPastedSomething =
true;
695 if (bPastedSomething) {
697 .
setTimes( t0, t0 + clipboard.Duration() );
716 auto range =
tracks.Selected();
717 auto last = *range.rbegin();
718 for (
auto n : range) {
719 if (!n->SupportsBasicEditing())
723 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1(),
false);
724 dest->MoveTo(std::max(selectedRegion.t0(), n->GetStartTime()));
746 auto &newClipboard = *pNewClipboard;
750 auto track = n.
SplitCut(selectedRegion.t0(), selectedRegion.t1());
751 newClipboard.Add(track);
755 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
756 n.
Silence(selectedRegion.t0(), selectedRegion.t1());
757 newClipboard.Add(dest);
763 clipboard.Assign(std::move(newClipboard),
764 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this());
767 .
PushState(
XO(
"Split-cut to the clipboard"),
XO(
"Split Cut"));
778 wt.
SplitDelete(selectedRegion.t0(), selectedRegion.t1());
781 if (n.SupportsBasicEditing())
782 n.Silence(selectedRegion.t0(), selectedRegion.t1());
787 XO(
"Split-deleted %.2f seconds at t=%.2f")
788 .
Format(selectedRegion.duration(), selectedRegion.t0()),
802 selectedWaveTracks.begin(), selectedWaveTracks.end(),
804 n->Silence(selectedRegion.t0(), selectedRegion.t1(), child);
810 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
811 .
Format(selectedRegion.duration(), selectedRegion.t0()),
813 XC(
"Silence",
"command"));
822 if (selectedRegion.isPoint())
827 wt.
Trim(selectedRegion.t0(), selectedRegion.t1());
831 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
832 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
842 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
843 pWaveTrack->Split(sel0, sel1);
850 wt->Split(sel0, sel1);
908 auto range =
tracks.Selected();
909 auto last = *range.rbegin();
910 for (
auto track : range) {
915 const double newt0 = wt.
SnapToSample(selectedRegion.t0());
916 const double newt1 = wt.
SnapToSample(selectedRegion.t1());
919 const auto dest = wt.
Copy(newt0, newt1,
false);
933 dest = n.Cut(viewInfo.selectedRegion.t0(),
934 viewInfo.selectedRegion.t1());
936 dest->MoveTo(std::max(0, n.GetOffset()));
960 selectedTracks.begin(), selectedTracks.end(),
963 selectedRegion.t0(), selectedRegion.t1(), childProgress);
969 XO(
"Joined %.2f seconds at t=%.2f")
970 .
Format(selectedRegion.duration(), selectedRegion.t0()),
981 wt->Disjoin(selectedRegion.t0(), selectedRegion.t1());
984 XO(
"Detached %.2f seconds at t=%.2f")
985 .
Format(selectedRegion.duration(), selectedRegion.t0()),
1006#if defined(__WXGTK__)
1014 wxRect r = window.GetRect();
1015 window.SetSize(wxSize(1,1));
1016 window.SetSize(r.GetSize());
1027 auto &selectedRegion =
project.GetViewInfo().selectedRegion;
1029 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
1031 selectedRegion.setT1(
1032 selectedRegion.t0() +
1033 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1054 if ( !range.empty() )
1077 if(viewInfo.selectedRegion.isPoint())
1081 for (
const auto track : selectedTracks)
1083 const auto selectedClips =
1085 viewInfo.selectedRegion.t0(), viewInfo.selectedRegion.t1());
1086 if(selectedClips.size() > 1)
1097 static const auto NotBusyTimeAndTracksFlags =
1101 static constexpr auto redoKey =
1111 static constexpr auto prefKey =
1119 static auto menu = std::shared_ptr{
1152 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+D") ),
1155 Menu(
wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1159 NotBusyTimeAndTracksFlags,
1163 NotBusyTimeAndTracksFlags,
1201 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+Alt+J") )
1224 static const auto flags =
1226 static auto menu = std::shared_ptr{
1277 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.
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.