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"
16#include "../TrackPanel.h"
27#include "../prefs/PrefsDialog.h"
28#include "../prefs/TracksBehaviorsPrefs.h"
29#include "../tracks/labeltrack/ui/LabelTrackView.h"
30#include "../tracks/playabletrack/wavetrack/ui/WaveChannelView.h"
32#include "../AudioPasteDialog.h"
58 if (view.PasteSelectedText(
project, selectedRegion.t0(),
59 selectedRegion.t1() ))
62 .
PushState(
XO(
"Pasted text from the clipboard"),
XO(
"Paste"));
66 if (view.CalcCursorX(
project, &x )) {
67 viewport.ScrollIntoView(x);
81 trackPanel.Refresh(
false);
93 const auto samplesCount =
95 result += samplesCount.as_long_long() *
103 BlockArray::size_type result{};
111 for (
auto track : src) {
113 track->Copy(track->GetStartTime(), track->GetEndTime(),
false);
114 pTrack->MoveTo(track->GetStartTime());
115 if (
const auto waveTrack =
dynamic_cast<WaveTrack*
>(pTrack.get()))
132 assert(
tracks.Selected().empty());
134 Track* pFirstNewTrack = NULL;
135 for (
auto pClip : src) {
138 pFirstNewTrack = pNewTrack.get();
147 const double srcTempo =
148 pFirstNewTrack ?
GetProjectTempo(*pFirstNewTrack).value_or(projTempo) :
153 const double quantT0 =
QUANTIZED_TIME(t0 * srcTempo / projTempo, projRate);
154 const double quantT1 =
QUANTIZED_TIME(t1 * srcTempo / projTempo, projRate);
155 selectedRegion.setTimes(
163 if (pFirstNewTrack) {
172 return std::any_of(range.begin(), range.end(),
174 return WaveTrackUtilities::HasHiddenData(*pTrack);
193 if (trackPanel.IsMouseCaptured()) {
201 auto t = *
tracks.Selected().begin();
221 if (trackPanel.IsMouseCaptured()) {
229 auto t = *
tracks.Selected().begin();
251 if (view.CutSelectedText( context.
project )) {
252 trackPanel.Refresh(
false);
261 if (view.CutSelectedText(context.
project)) {
262 trackPanel.Refresh(
false);
271 auto &newClipboard = *pNewClipboard;
277 auto dest = n.
Cut(selectedRegion.t0(), selectedRegion.t1());
278 newClipboard.Add(dest);
283 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
284 newClipboard.Add(dest);
291 std::move( newClipboard ),
308 [&](
auto &&fallthrough){
return [&](
WaveTrack &wt) {
310 wt.ClearAndAddCutLine(selectedRegion.t0(), selectedRegion.t1());
316 n.
Clear(selectedRegion.t0(), selectedRegion.t1());
320 selectedRegion.collapseToT0();
327 ruler.DrawOverlays(
true );
337 if (!n->SupportsBasicEditing())
340 n->Clear(selectedRegion.t0(), selectedRegion.t1());
344 double seconds = selectedRegion.
duration();
346 selectedRegion.collapseToT0();
349 XO(
"Deleted %.2f seconds at t=%.2f")
350 .
Format( seconds, selectedRegion.t0()),
364 if (view.CopySelectedText( context.
project )) {
373 if (view.CopySelectedText(context.
project)) {
382 auto &newClipboard = *pNewClipboard;
384 for (
auto n :
tracks.Selected()) {
385 if (n->SupportsBasicEditing()) {
386 auto dest = n->Copy(selectedRegion.t0(), selectedRegion.t1());
387 newClipboard.Add(dest);
392 clipboard.Assign( std::move( newClipboard ),
393 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this() );
396 trackPanel.Refresh(
false);
401 double sel0 = 0.0, sel1 = 0.0;
406 auto &selectedRegion = *pRegion;
407 sel0 = selectedRegion.t0();
408 sel1 = selectedRegion.t1();
414 sel0 = selectedRegion.
t0();
415 sel1 = selectedRegion.t1();
418 return { sel0, sel1 };
427 auto discardTrimmed =
false;
428 if (&context.
project != &*clipboard.Project().lock()) {
430 if (waveClipCopyPolicy ==
wxT(
"Ask") &&
437 const auto result = audioPasteDialog.ShowModal();
438 if(result == wxID_CANCEL)
443 else if(waveClipCopyPolicy ==
wxT(
"Discard"))
444 discardTrimmed =
true;
447 std::shared_ptr<const TrackList> srcTracks;
451 srcTracks = clipboard.GetTracks().shared_from_this();
462 auto &pSampleBlockFactory = trackFactory.GetSampleBlockFactory();
463 return pSampleBlockFactory->Subscribe([
466 copyStartTime = std::chrono::system_clock::now(),
467 progressDialog = std::shared_ptr<BasicUI::ProgressDialog>()]
469 using namespace std::chrono;
470 constexpr auto ProgressDialogShowDelay = milliseconds { 100 };
472 if(!progressDialog) {
473 if(duration_cast<milliseconds>(system_clock::now() - copyStartTime) >= ProgressDialogShowDelay)
477 progressDialog->Poll(nCopied, toCopy);
500 auto dstRange = dstTracks.
Selected();
501 if (dstRange.size() == 1)
504 dstRange = dstTracks.
Any().StartingWith(*dstRange.begin());
505 auto srcRange = srcTracks.
Any();
506 while (!(dstRange.empty() || srcRange.empty())) {
507 auto &dst = **dstRange.begin();
508 auto &src = **srcRange.begin();
514 result.emplace_back(&dst, &src);
519 if (!srcRange.empty())
535 if (clipboard.GetTracks().empty())
549 project, *srcTracks, clipboard.T0(), clipboard.T1());
556 auto newT1 = t0 + clipboard.Duration();
560 bool bPastedSomething =
false;
564 if (correspondence.empty()) {
565 if (
tracks.Selected().size() == 1)
567"The content you are trying to paste will span across more tracks than you "
568"currently have available. Add more tracks and try again.")
572"There are not enough tracks selected to accommodate your copied content. "
573"Select additional tracks and try again.")
577 auto iPair = correspondence.begin();
578 const auto endPair = correspondence.cend();
581 auto next =
tracks.begin();
582 for (
auto range =
tracks.Any(); !range.empty();
586 if (iPair == endPair)
590 next =
tracks.Find(*group.rbegin());
593 if (!group.contains(iPair->first))
598 for (
auto member : group) {
599 if (iPair == endPair || member != iPair->first) {
602 if (t1 != newT1 && t1 <= member->GetEndTime()) {
603 member->SyncLockAdjust(t1, newT1);
604 bPastedSomething =
true;
613 const auto src = (iPair++)->second;
616 bPastedSomething =
true;
619 const auto newClipOnPaste =
627 const auto merge = newClipOnPaste ? false :
true;
628 const auto preserveExistingBoundaries = newClipOnPaste ? false :
true;
629 auto clearByTrimming = newClipOnPaste ? true :
false;
631 t0, t1, *
static_cast<const WaveTrack*
>(src),
632 preserveExistingBoundaries, merge, &warper,
640 ln.ShiftLabelsOnInsert( clipboard.Duration(), t0 );
642 bPastedSomething |= ln.PasteOver(t0, *src);
645 bPastedSomething =
true;
656 if (bPastedSomething) {
658 .
setTimes( t0, t0 + clipboard.Duration() );
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(), selectedRegion.t1(),
false);
685 dest->MoveTo(std::max(selectedRegion.t0(), n->GetStartTime()));
707 auto &newClipboard = *pNewClipboard;
711 auto track = n.
SplitCut(selectedRegion.t0(), selectedRegion.t1());
712 newClipboard.Add(track);
716 auto dest = n.
Copy(selectedRegion.t0(), selectedRegion.t1());
717 n.
Silence(selectedRegion.t0(), selectedRegion.t1());
718 newClipboard.Add(dest);
724 clipboard.Assign(std::move(newClipboard),
725 selectedRegion.t0(), selectedRegion.t1(),
project.shared_from_this());
728 .
PushState(
XO(
"Split-cut to the clipboard"),
XO(
"Split Cut"));
739 wt.
SplitDelete(selectedRegion.t0(), selectedRegion.t1());
742 if (n.SupportsBasicEditing())
743 n.Silence(selectedRegion.t0(), selectedRegion.t1());
748 XO(
"Split-deleted %.2f seconds at t=%.2f")
749 .
Format(selectedRegion.duration(), selectedRegion.t0()),
763 selectedWaveTracks.begin(), selectedWaveTracks.end(),
765 n->Silence(selectedRegion.t0(), selectedRegion.t1(), child);
771 XO(
"Silenced selected tracks for %.2f seconds at %.2f")
772 .
Format(selectedRegion.duration(), selectedRegion.t0()),
774 XC(
"Silence",
"command"));
783 if (selectedRegion.isPoint())
788 wt.
Trim(selectedRegion.t0(), selectedRegion.t1());
792 XO(
"Trim selected audio tracks from %.2f seconds to %.2f seconds")
793 .
Format( selectedRegion.t0(), selectedRegion.t1() ),
803 if (
auto pWaveTrack =
dynamic_cast<WaveTrack*
>(pTrack))
804 pWaveTrack->Split(sel0, sel1);
811 wt->Split(sel0, sel1);
869 auto range =
tracks.Selected();
870 auto last = *range.rbegin();
871 for (
auto track : range) {
876 const double newt0 = wt.
SnapToSample(selectedRegion.t0());
877 const double newt1 = wt.
SnapToSample(selectedRegion.t1());
880 const auto dest = wt.
Copy(newt0, newt1,
false);
894 dest = n.Cut(viewInfo.selectedRegion.t0(),
895 viewInfo.selectedRegion.t1());
897 dest->MoveTo(std::max(0, n.GetOffset()));
921 selectedTracks.begin(), selectedTracks.end(),
924 selectedRegion.t0(), selectedRegion.t1(), childProgress);
930 XO(
"Joined %.2f seconds at t=%.2f")
931 .
Format(selectedRegion.duration(), selectedRegion.t0()),
942 wt->Disjoin(selectedRegion.t0(), selectedRegion.t1());
945 XO(
"Detached %.2f seconds at t=%.2f")
946 .
Format(selectedRegion.duration(), selectedRegion.t0()),
967#if defined(__WXGTK__)
975 wxRect r = window.GetRect();
976 window.SetSize(wxSize(1,1));
977 window.SetSize(r.GetSize());
988 auto &selectedRegion =
project.GetViewInfo().selectedRegion;
990 if((AudacityProject::msClipT1 - AudacityProject::msClipT0) > 0.0)
992 selectedRegion.setT1(
993 selectedRegion.t0() +
994 (AudacityProject::msClipT1 - AudacityProject::msClipT0));
1015 if ( !range.empty() )
1038 if(viewInfo.selectedRegion.isPoint())
1042 for (
const auto track : selectedTracks)
1044 const auto selectedClips =
1046 viewInfo.selectedRegion.t0(), viewInfo.selectedRegion.t1());
1047 if(selectedClips.size() > 1)
1058 static const auto NotBusyTimeAndTracksFlags =
1062 static constexpr auto redoKey =
1072 static constexpr auto prefKey =
1080 static auto menu = std::shared_ptr{
1113 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+D") ),
1116 Menu(
wxT(
"RemoveSpecial"),
XXO(
"R&emove Special"),
1120 NotBusyTimeAndTracksFlags,
1124 NotBusyTimeAndTracksFlags,
1162 NotBusyTimeAndTracksFlags,
wxT(
"Ctrl+Alt+J") )
1185 static const auto flags =
1187 static auto menu = std::shared_ptr{
1238 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)
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)
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.