mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-03 09:29:30 +02:00
TrackPanel no longer implements the time shift tool...
... also implement ESC key for it
This commit is contained in:
parent
f1f254f974
commit
251976d93d
@ -1205,6 +1205,7 @@
|
||||
28FE4A080ABF4E960056F5C4 /* mmx_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28FE4A060ABF4E960056F5C4 /* mmx_optimized.cpp */; };
|
||||
28FE4A090ABF4E960056F5C4 /* sse_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28FE4A070ABF4E960056F5C4 /* sse_optimized.cpp */; };
|
||||
5E000A211EC7B5D500E8FD93 /* SampleHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E000A1F1EC7B5D500E8FD93 /* SampleHandle.cpp */; };
|
||||
5E7396441DAFD8C600BA0A4D /* TimeShiftHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */; };
|
||||
5E02BFF21D1164DF00EB7578 /* Distortion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E02BFF01D1164DF00EB7578 /* Distortion.cpp */; };
|
||||
5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; };
|
||||
5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842F1DF1E4F400CA76EA /* UserException.cpp */; };
|
||||
@ -3004,6 +3005,8 @@
|
||||
28FEC1B21A12B6FB00FACE48 /* EffectAutomationParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EffectAutomationParameters.h; path = ../include/audacity/EffectAutomationParameters.h; sourceTree = SOURCE_ROOT; };
|
||||
5E000A1F1EC7B5D500E8FD93 /* SampleHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SampleHandle.cpp; sourceTree = "<group>"; };
|
||||
5E000A201EC7B5D500E8FD93 /* SampleHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SampleHandle.h; sourceTree = "<group>"; };
|
||||
5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeShiftHandle.cpp; sourceTree = "<group>"; };
|
||||
5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeShiftHandle.h; sourceTree = "<group>"; };
|
||||
5E02BFF01D1164DF00EB7578 /* Distortion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Distortion.cpp; sourceTree = "<group>"; };
|
||||
5E02BFF11D1164DF00EB7578 /* Distortion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Distortion.h; sourceTree = "<group>"; };
|
||||
5E07842C1DEE6B8600CA76EA /* FileException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileException.cpp; sourceTree = "<group>"; };
|
||||
@ -5732,6 +5735,7 @@
|
||||
5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */,
|
||||
5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */,
|
||||
5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */,
|
||||
5E7396421DAFD8C600BA0A4D /* TimeShiftHandle.cpp */,
|
||||
5E1512681DB0010C00702E29 /* TrackControls.cpp */,
|
||||
5E15126A1DB0010C00702E29 /* TrackUI.cpp */,
|
||||
5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */,
|
||||
@ -5740,6 +5744,7 @@
|
||||
5E74D2DE1CC4429700D88B0B /* EditCursorOverlay.h */,
|
||||
5E74D2E01CC4429700D88B0B /* PlayIndicatorOverlay.h */,
|
||||
5E74D2E21CC4429700D88B0B /* Scrubbing.h */,
|
||||
5E7396431DAFD8C600BA0A4D /* TimeShiftHandle.h */,
|
||||
5E1512691DB0010C00702E29 /* TrackControls.h */,
|
||||
5E15126C1DB0010C00702E29 /* TrackVRulerControls.h */,
|
||||
5E73963D1DAFD86000BA0A4D /* ZoomHandle.h */,
|
||||
@ -7844,6 +7849,7 @@
|
||||
EDAD326E1544452E009C6220 /* sv.po in Sources */,
|
||||
ED87F50A1986424100AC520B /* ta.po in Sources */,
|
||||
2888496E131B6CF600B59735 /* tg.po in Sources */,
|
||||
5E7396441DAFD8C600BA0A4D /* TimeShiftHandle.cpp in Sources */,
|
||||
2888496F131B6CF600B59735 /* tr.po in Sources */,
|
||||
28884970131B6CF600B59735 /* uk.po in Sources */,
|
||||
28884971131B6CF600B59735 /* vi.po in Sources */,
|
||||
|
@ -60,6 +60,7 @@ for drawing different aspects of the label and its text box.
|
||||
#include "AColor.h"
|
||||
#include "Project.h"
|
||||
#include "TrackArtist.h"
|
||||
#include "Snap.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "UndoManager.h"
|
||||
#include "commands/CommandManager.h"
|
||||
|
@ -579,6 +579,8 @@ audacity_SOURCES = \
|
||||
tracks/ui/PlayIndicatorOverlay.h \
|
||||
tracks/ui/Scrubbing.cpp \
|
||||
tracks/ui/Scrubbing.h \
|
||||
tracks/ui/TimeShiftHandle.cpp \
|
||||
tracks/ui/TimeShiftHandle.h \
|
||||
tracks/ui/TrackControls.cpp \
|
||||
tracks/ui/TrackControls.h \
|
||||
tracks/ui/TrackUI.cpp \
|
||||
|
@ -461,7 +461,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
||||
}
|
||||
|
||||
mMouseCapture = IsUncaptured;
|
||||
mSlideUpDownOnly = false;
|
||||
mLabelTrackStartXPos=-1;
|
||||
|
||||
|
||||
@ -470,7 +469,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
||||
mSelectCursor = MakeCursor( wxCURSOR_IBEAM, IBeamCursorXpm, 17, 16);
|
||||
mEnvelopeCursor= MakeCursor( wxCURSOR_ARROW, EnvCursorXpm, 16, 16);
|
||||
mDisabledCursor= MakeCursor( wxCURSOR_NO_ENTRY, DisabledCursorXpm,16, 16);
|
||||
mSlideCursor = MakeCursor( wxCURSOR_SIZEWE, TimeCursorXpm, 16, 16);
|
||||
mZoomInCursor = MakeCursor( wxCURSOR_MAGNIFIER, ZoomInCursorXpm, 19, 15);
|
||||
mZoomOutCursor = MakeCursor( wxCURSOR_MAGNIFIER, ZoomOutCursorXpm, 19, 15);
|
||||
|
||||
@ -1152,7 +1150,6 @@ void TrackPanel::HandleInterruptedDrag()
|
||||
IsClosing,
|
||||
IsAdjustingLabel,
|
||||
IsRearranging,
|
||||
IsSliding,
|
||||
IsEnveloping,
|
||||
IsGainSliding,
|
||||
IsPanSliding,
|
||||
@ -1409,9 +1406,6 @@ bool TrackPanel::SetCursorByActivity( )
|
||||
case IsSelecting:
|
||||
SetCursor(*mSelectCursor);
|
||||
return true;
|
||||
case IsSliding:
|
||||
SetCursor( unsafe ? *mDisabledCursor : *mSlideCursor);
|
||||
return true;
|
||||
case IsEnveloping:
|
||||
SetCursor( unsafe ? *mDisabledCursor : *mEnvelopeCursor);
|
||||
return true;
|
||||
@ -1766,9 +1760,6 @@ void TrackPanel::SetCursorAndTipByTool( int tool,
|
||||
case envelopeTool:
|
||||
SetCursor(unsafe ? *mDisabledCursor : *mEnvelopeCursor);
|
||||
break;
|
||||
case slideTool:
|
||||
SetCursor(unsafe ? *mDisabledCursor : *mSlideCursor);
|
||||
break;
|
||||
}
|
||||
// doesn't actually change the tip itself, but it could (should?) do at some
|
||||
// future date.
|
||||
@ -3312,105 +3303,71 @@ void TrackPanel::ForwardEventToEnvelope(wxMouseEvent & event)
|
||||
}
|
||||
}
|
||||
|
||||
void TrackPanel::HandleSlide( wxMouseEvent & event )
|
||||
// Helper for the above, adds a track's clips to mCapturedClipArray (eliminates
|
||||
// duplication of this logic)
|
||||
void TrackPanel::AddClipsToCaptured
|
||||
( ClipMoveState &state, const ViewInfo &viewInfo,
|
||||
Track *t, bool withinSelection )
|
||||
{
|
||||
if (event.LeftDown())
|
||||
StartSlide(event);
|
||||
if (withinSelection)
|
||||
AddClipsToCaptured( state, t, viewInfo.selectedRegion.t0(),
|
||||
viewInfo.selectedRegion.t1() );
|
||||
else
|
||||
AddClipsToCaptured( state, t, t->GetStartTime(), t->GetEndTime() );
|
||||
}
|
||||
|
||||
if (mMouseCapture != IsSliding)
|
||||
// Adds a track's clips to state.capturedClipArray within a specified time
|
||||
void TrackPanel::AddClipsToCaptured
|
||||
( ClipMoveState &state, Track *t, double t0, double t1 )
|
||||
{
|
||||
if (t->GetKind() == Track::Wave)
|
||||
{
|
||||
for(const auto &clip: static_cast<WaveTrack*>(t)->GetClips())
|
||||
{
|
||||
if ( ! clip->AfterClip(t0) && ! clip->BeforeClip(t1) )
|
||||
{
|
||||
// Avoid getting clips that were already captured
|
||||
bool newClip = true;
|
||||
for (unsigned int i = 0; i < state.capturedClipArray.size(); ++i) {
|
||||
if ( state.capturedClipArray[i].clip == clip.get() ) {
|
||||
newClip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newClip)
|
||||
state.capturedClipArray.push_back( TrackClip(t, clip.get()) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This handles label tracks rather heavy-handedly -- it would be nice to
|
||||
// treat individual labels like clips
|
||||
|
||||
// Avoid adding a track twice
|
||||
bool newClip = true;
|
||||
for ( unsigned int i = 0; i < state.capturedClipArray.size(); ++i ) {
|
||||
if ( state.capturedClipArray[i].track == t ) {
|
||||
newClip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newClip) {
|
||||
#ifdef USE_MIDI
|
||||
// do not add NoteTrack if the data is outside of time bounds
|
||||
if (t->GetKind() == Track::Note) {
|
||||
if (t->GetEndTime() < t0 || t->GetStartTime() > t1)
|
||||
return;
|
||||
|
||||
if (event.Dragging() && mCapturedTrack)
|
||||
DoSlide(event);
|
||||
|
||||
if (event.LeftUp()) {
|
||||
|
||||
SetCapturedTrack( NULL );
|
||||
|
||||
mSnapManager.reset();
|
||||
|
||||
// Do not draw yellow lines
|
||||
if ( mClipMoveState.snapLeft != -1 || mClipMoveState.snapRight != -1) {
|
||||
mClipMoveState.snapLeft = mClipMoveState.snapRight = -1;
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
if (!mDidSlideVertically && mClipMoveState.hSlideAmount == 0)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < mClipMoveState.capturedClipArray.size(); i++)
|
||||
{
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[i];
|
||||
WaveClip* pWaveClip = trackClip.clip;
|
||||
// Note that per TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1),
|
||||
// in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray,
|
||||
// so we have to check for that any time we're going to deref it.
|
||||
// Previous code did not check it here, and that caused bug 367 crash.
|
||||
if (pWaveClip &&
|
||||
trackClip.track != trackClip.origTrack)
|
||||
{
|
||||
// Now that user has dropped the clip into a different track,
|
||||
// make sure the sample rate matches the destination track (mCapturedTrack).
|
||||
// Assume the clip was dropped in a wave track
|
||||
pWaveClip->Resample
|
||||
(static_cast<WaveTrack*>(trackClip.track)->GetRate());
|
||||
pWaveClip->MarkChanged();
|
||||
#endif
|
||||
state.capturedClipArray.push_back(TrackClip(t, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
MakeParentRedrawScrollbars();
|
||||
|
||||
wxString msg;
|
||||
bool consolidate;
|
||||
if (mDidSlideVertically) {
|
||||
msg.Printf(_("Moved clips to another track"));
|
||||
consolidate = false;
|
||||
}
|
||||
else {
|
||||
wxString direction = mClipMoveState.hSlideAmount > 0 ?
|
||||
/* i18n-hint: a direction as in left or right.*/
|
||||
_("right") :
|
||||
/* i18n-hint: a direction as in left or right.*/
|
||||
_("left");
|
||||
/* i18n-hint: %s is a direction like left or right */
|
||||
msg.Printf(_("Time shifted tracks/clips %s %.02f seconds"),
|
||||
direction.c_str(), fabs( mClipMoveState.hSlideAmount ));
|
||||
consolidate = true;
|
||||
}
|
||||
MakeParentPushState(msg, _("Time-Shift"),
|
||||
consolidate ? (UndoPush::CONSOLIDATE) : (UndoPush::AUTOSAVE));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Don't count right channels.
|
||||
WaveTrack *NthAudioTrack(TrackList &list, int nn)
|
||||
{
|
||||
if (nn >= 0) {
|
||||
TrackListOfKindIterator iter(Track::Wave, &list);
|
||||
Track *pTrack = iter.First();
|
||||
while (pTrack && nn--)
|
||||
pTrack = iter.Next(true);
|
||||
return static_cast<WaveTrack*>(pTrack);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Don't count right channels.
|
||||
int TrackPosition(TrackList &list, Track *pFindTrack)
|
||||
{
|
||||
Track *const partner = pFindTrack->GetLink();
|
||||
TrackListOfKindIterator iter(Track::Wave, &list);
|
||||
int nn = 0;
|
||||
for (Track *pTrack = iter.First(); pTrack; pTrack = iter.Next(true), ++nn) {
|
||||
if (pTrack == pFindTrack ||
|
||||
pTrack == partner)
|
||||
return nn;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
WaveClip *FindClipAtTime(WaveTrack *pTrack, double time)
|
||||
{
|
||||
if (pTrack) {
|
||||
@ -3427,87 +3384,6 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepare for sliding.
|
||||
void TrackPanel::StartSlide(wxMouseEvent & event)
|
||||
{
|
||||
mClipMoveState.clear();
|
||||
|
||||
mDidSlideVertically = false;
|
||||
|
||||
const auto foundCell = FindCell(event.m_x, event.m_y);
|
||||
auto &vt = foundCell.pTrack;
|
||||
if (!vt || foundCell.type != CellType::Track)
|
||||
return;
|
||||
auto &rect = foundCell.rect;
|
||||
|
||||
ToolsToolBar * ttb = mListener->TP_GetToolsToolBar();
|
||||
bool multiToolModeActive = (ttb && ttb->IsDown(multiTool));
|
||||
|
||||
double clickTime =
|
||||
mViewInfo->PositionToTime(event.m_x, GetLeftOffset());
|
||||
mClipMoveState.capturedClipIsSelection =
|
||||
(vt->GetSelected() &&
|
||||
clickTime > mViewInfo->selectedRegion.t0() &&
|
||||
clickTime < mViewInfo->selectedRegion.t1());
|
||||
|
||||
WaveTrack *wt = vt->GetKind() == Track::Wave
|
||||
? static_cast<WaveTrack*>(vt) : nullptr;
|
||||
|
||||
if ((wt
|
||||
#ifdef USE_MIDI
|
||||
|| vt->GetKind() == Track::Note
|
||||
#endif
|
||||
) && !event.ShiftDown())
|
||||
{
|
||||
#ifdef USE_MIDI
|
||||
if (!wt)
|
||||
mClipMoveState.capturedClip = NULL;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mClipMoveState.capturedClip = wt->GetClipAtX(event.m_x);
|
||||
if (mClipMoveState.capturedClip == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
mCapturedTrack = vt;
|
||||
CreateListOfCapturedClips
|
||||
( mClipMoveState, *mViewInfo, *mCapturedTrack, *GetTracks(),
|
||||
GetProject()->IsSyncLocked(), clickTime );
|
||||
|
||||
} else {
|
||||
mClipMoveState.capturedClip = NULL;
|
||||
mClipMoveState.capturedClipArray.clear();
|
||||
mCapturedTrack = vt;
|
||||
}
|
||||
|
||||
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
||||
|
||||
mCapturedRect = rect;
|
||||
|
||||
mMouseClickX = event.m_x;
|
||||
mMouseClickY = event.m_y;
|
||||
|
||||
mSelStartValid = true;
|
||||
mSelStart = mViewInfo->PositionToTime(event.m_x, rect.x);
|
||||
|
||||
mSnapManager = std::make_unique<SnapManager>(GetTracks(),
|
||||
mViewInfo,
|
||||
&mClipMoveState.capturedClipArray,
|
||||
&mClipMoveState.trackExclusions,
|
||||
true); // don't snap to time
|
||||
mClipMoveState.snapLeft = -1;
|
||||
mClipMoveState.snapRight = -1;
|
||||
mSnapPreferRightEdge = false;
|
||||
if (mClipMoveState.capturedClip) {
|
||||
if (fabs(mSelStart - mClipMoveState.capturedClip->GetEndTime()) <
|
||||
fabs(mSelStart - mClipMoveState.capturedClip->GetStartTime()))
|
||||
mSnapPreferRightEdge = true;
|
||||
}
|
||||
|
||||
mMouseCapture = IsSliding;
|
||||
}
|
||||
|
||||
void TrackPanel::CreateListOfCapturedClips
|
||||
( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack,
|
||||
TrackList &trackList, bool syncLocked, double clickTime )
|
||||
@ -3589,6 +3465,7 @@ void TrackPanel::CreateListOfCapturedClips
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Helper for the above, adds a track's clips to mCapturedClipArray (eliminates
|
||||
// duplication of this logic)
|
||||
void TrackPanel::AddClipsToCaptured
|
||||
@ -3652,261 +3529,7 @@ void TrackPanel::AddClipsToCaptured
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Slide tracks horizontally, or slide clips horizontally or vertically
|
||||
/// (e.g. moving clips between tracks).
|
||||
|
||||
// GM: DoSlide now implementing snap-to
|
||||
// samples functionality based on sample rate.
|
||||
void TrackPanel::DoSlide(wxMouseEvent & event)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// find which track the mouse is currently in (mouseTrack) -
|
||||
// this may not be the same as the one we started in...
|
||||
|
||||
const auto foundCell = FindCell(event.m_x, event.m_y);
|
||||
if (foundCell.type != CellType::Track)
|
||||
// Allow sliding only if x is
|
||||
// within the bounds of the tracks area.
|
||||
return;
|
||||
|
||||
auto mouseTrack = foundCell.pTrack;
|
||||
if (mouseTrack == nullptr) {
|
||||
// Allow sliding if the pointer is not over any track.
|
||||
mouseTrack = mCapturedTrack;
|
||||
}
|
||||
|
||||
// Start by undoing the current slide amount; everything
|
||||
// happens relative to the original horizontal position of
|
||||
// each clip...
|
||||
#ifdef USE_MIDI
|
||||
if ( mClipMoveState.capturedClipArray.size() )
|
||||
#else
|
||||
if ( mClipMoveState.capturedClip )
|
||||
#endif
|
||||
{
|
||||
for ( i = 0; i < mClipMoveState.capturedClipArray.size(); ++i ) {
|
||||
if ( mClipMoveState.capturedClipArray[i].clip )
|
||||
mClipMoveState.capturedClipArray[i].clip->Offset
|
||||
( -mClipMoveState.hSlideAmount );
|
||||
else
|
||||
mClipMoveState.capturedClipArray[i].track->Offset
|
||||
( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
}
|
||||
else {
|
||||
mCapturedTrack->Offset( -mClipMoveState.hSlideAmount );
|
||||
Track* link = mCapturedTrack->GetLink();
|
||||
if (link)
|
||||
link->Offset( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
|
||||
if ( mClipMoveState.capturedClipIsSelection ) {
|
||||
// Slide the selection, too
|
||||
mViewInfo->selectedRegion.move( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
mClipMoveState.hSlideAmount = 0.0;
|
||||
|
||||
// Implement sliding within the track(s)
|
||||
double desiredSlideAmount;
|
||||
if (mSlideUpDownOnly) {
|
||||
desiredSlideAmount = 0.0;
|
||||
}
|
||||
else {
|
||||
desiredSlideAmount =
|
||||
mViewInfo->PositionToTime(event.m_x) -
|
||||
mViewInfo->PositionToTime(mMouseClickX);
|
||||
bool trySnap = false;
|
||||
double clipLeft = 0, clipRight = 0;
|
||||
#ifdef USE_MIDI
|
||||
if (mouseTrack->GetKind() == Track::Wave) {
|
||||
WaveTrack *mtw = (WaveTrack *)mouseTrack;
|
||||
desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) /
|
||||
mtw->GetRate(); // set it to a sample point
|
||||
}
|
||||
// Adjust desiredSlideAmount using SnapManager
|
||||
if (mSnapManager && mClipMoveState.capturedClipArray.size()) {
|
||||
trySnap = true;
|
||||
if ( mClipMoveState.capturedClip ) {
|
||||
clipLeft = mClipMoveState.capturedClip->GetStartTime()
|
||||
+ desiredSlideAmount;
|
||||
clipRight = mClipMoveState.capturedClip->GetEndTime()
|
||||
+ desiredSlideAmount;
|
||||
}
|
||||
else {
|
||||
clipLeft = mCapturedTrack->GetStartTime() + desiredSlideAmount;
|
||||
clipRight = mCapturedTrack->GetEndTime() + desiredSlideAmount;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
trySnap = true;
|
||||
if (mouseTrack->GetKind() == Track::Wave) {
|
||||
WaveTrack *mtw = (WaveTrack *)mouseTrack;
|
||||
desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) /
|
||||
mtw->GetRate(); // set it to a sample point
|
||||
}
|
||||
if (mSnapManager && mClipMoveState.capturedClip) {
|
||||
clipLeft = mClipMoveState.capturedClip->GetStartTime() + desiredSlideAmount;
|
||||
clipRight = mClipMoveState.capturedClip->GetEndTime() + desiredSlideAmount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (trySnap) {
|
||||
double newClipLeft = clipLeft;
|
||||
double newClipRight = clipRight;
|
||||
|
||||
bool dummy1, dummy2;
|
||||
mSnapManager->Snap(mCapturedTrack, clipLeft, false, &newClipLeft,
|
||||
&dummy1, &dummy2);
|
||||
mSnapManager->Snap(mCapturedTrack, clipRight, false, &newClipRight,
|
||||
&dummy1, &dummy2);
|
||||
|
||||
// Only one of them is allowed to snap
|
||||
if (newClipLeft != clipLeft && newClipRight != clipRight) {
|
||||
if (mSnapPreferRightEdge)
|
||||
newClipLeft = clipLeft;
|
||||
else
|
||||
newClipRight = clipRight;
|
||||
}
|
||||
|
||||
// Take whichever one snapped (if any) and compute the NEW desiredSlideAmount
|
||||
mClipMoveState.snapLeft = -1;
|
||||
mClipMoveState.snapRight = -1;
|
||||
if (newClipLeft != clipLeft) {
|
||||
double difference = (newClipLeft - clipLeft);
|
||||
desiredSlideAmount += difference;
|
||||
mClipMoveState.snapLeft =
|
||||
mViewInfo->TimeToPosition(newClipLeft, GetLeftOffset());
|
||||
}
|
||||
else if (newClipRight != clipRight) {
|
||||
double difference = (newClipRight - clipRight);
|
||||
desiredSlideAmount += difference;
|
||||
mClipMoveState.snapRight =
|
||||
mViewInfo->TimeToPosition(newClipRight, GetLeftOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll during vertical drag.
|
||||
// EnsureVisible(mouseTrack); //vvv Gale says this has problems on Linux, per bug 393 thread. Revert for 2.0.2.
|
||||
bool slidVertically = false;
|
||||
|
||||
// If the mouse is over a track that isn't the captured track,
|
||||
// decide which tracks the captured clips should go to.
|
||||
if ( mClipMoveState.capturedClip && mouseTrack != mCapturedTrack /*&&
|
||||
!mCapturedClipIsSelection*/ )
|
||||
{
|
||||
const int diff =
|
||||
TrackPosition(*mTracks, mouseTrack) -
|
||||
TrackPosition(*mTracks, mCapturedTrack);
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii ) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
if (trackClip.clip) {
|
||||
// Move all clips up or down by an equal count of audio tracks.
|
||||
Track *const pSrcTrack = trackClip.track;
|
||||
auto pDstTrack = NthAudioTrack(*mTracks,
|
||||
diff + TrackPosition(*mTracks, pSrcTrack));
|
||||
// Can only move mono to mono, or left to left, or right to right
|
||||
// And that must be so for each captured clip
|
||||
bool stereo = (pSrcTrack->GetLink() != 0);
|
||||
if (pDstTrack && stereo && !pSrcTrack->GetLinked())
|
||||
// Assume linked track is wave or null
|
||||
pDstTrack = static_cast<WaveTrack*>(pDstTrack->GetLink());
|
||||
bool ok = pDstTrack &&
|
||||
(stereo == (pDstTrack->GetLink() != 0)) &&
|
||||
(!stereo || (pSrcTrack->GetLinked() == pDstTrack->GetLinked()));
|
||||
if (ok)
|
||||
trackClip.dstTrack = pDstTrack;
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Having passed that test, remove clips temporarily from their
|
||||
// tracks, so moving clips don't interfere with each other
|
||||
// when we call CanInsertClip()
|
||||
for ( unsigned ii = 0,
|
||||
nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii ) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
trackClip.holder =
|
||||
// Assume track is wave because it has a clip
|
||||
static_cast<WaveTrack*>(trackClip.track)->
|
||||
RemoveAndReturnClip(pSrcClip);
|
||||
}
|
||||
|
||||
// Now check that the move is possible
|
||||
bool ok = true;
|
||||
for ( unsigned ii = 0,
|
||||
nn = mClipMoveState.capturedClipArray.size(); ok && ii < nn; ++ii) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
ok = trackClip.dstTrack->CanInsertClip(pSrcClip);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// Failure -- put clips back where they were
|
||||
for ( unsigned ii = 0,
|
||||
nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
// Assume track is wave because it has a clip
|
||||
static_cast<WaveTrack*>(trackClip.track)->
|
||||
AddClip(std::move(trackClip.holder));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Do the vertical moves of clips
|
||||
for ( unsigned ii = 0,
|
||||
nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip) {
|
||||
const auto dstTrack = trackClip.dstTrack;
|
||||
dstTrack->AddClip(std::move(trackClip.holder));
|
||||
trackClip.track = dstTrack;
|
||||
}
|
||||
}
|
||||
|
||||
mCapturedTrack = mouseTrack;
|
||||
mDidSlideVertically = true;
|
||||
|
||||
// Make the offset permanent; start from a "clean slate"
|
||||
mMouseClickX = event.m_x;
|
||||
}
|
||||
|
||||
// Not done yet, check for horizontal movement.
|
||||
slidVertically = true;
|
||||
}
|
||||
|
||||
if (desiredSlideAmount == 0.0) {
|
||||
Refresh(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mClipMoveState.hSlideAmount = desiredSlideAmount;
|
||||
|
||||
DoSlideHorizontal( mClipMoveState, *GetTracks(), *mCapturedTrack );
|
||||
|
||||
|
||||
if ( mClipMoveState.capturedClipIsSelection ) {
|
||||
// Slide the selection, too
|
||||
mViewInfo->selectedRegion.move( mClipMoveState.hSlideAmount );
|
||||
}
|
||||
|
||||
if (slidVertically) {
|
||||
// NEW origin
|
||||
mClipMoveState.hSlideAmount = 0;
|
||||
}
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
void TrackPanel::DoSlideHorizontal
|
||||
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack )
|
||||
@ -6543,10 +6166,6 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
|
||||
if (!unsafe)
|
||||
HandleEnvelope(event);
|
||||
break;
|
||||
case slideTool:
|
||||
if (!unsafe)
|
||||
HandleSlide(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6554,8 +6173,7 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
|
||||
if ((event.Moving() || event.LeftUp()) &&
|
||||
(mMouseCapture == IsUncaptured ))
|
||||
// (mMouseCapture != IsSelecting ) &&
|
||||
// (mMouseCapture != IsEnveloping) &&
|
||||
// (mMouseCapture != IsSliding) )
|
||||
// (mMouseCapture != IsEnveloping)
|
||||
{
|
||||
HandleCursor(event);
|
||||
}
|
||||
@ -6608,14 +6226,8 @@ int TrackPanel::DetermineToolToUse( ToolsToolBar * pTtb, const wxMouseEvent & ev
|
||||
// From here on the order in which we hit test determines
|
||||
// which tool takes priority in the rare cases where it
|
||||
// could be more than one.
|
||||
} else if (event.CmdDown()){
|
||||
// msmeyer: If control is down, slide single clip
|
||||
// msmeyer: If control and shift are down, slide all clips
|
||||
currentTool = slideTool;
|
||||
} else if( HitTestEnvelope( pTrack, rect, event ) ) {
|
||||
currentTool = envelopeTool;
|
||||
} else if( HitTestSlide( pTrack, rect, event )){
|
||||
currentTool = slideTool;
|
||||
}
|
||||
|
||||
//Use the false argument since in multimode we don't
|
||||
@ -6725,28 +6337,6 @@ bool TrackPanel::HitTestEnvelope(Track *track, const wxRect &rect, const wxMouse
|
||||
return( distance < yTolerance );
|
||||
}
|
||||
|
||||
/// method that tells us if the mouse event landed on a
|
||||
/// time-slider that allows us to time shift the sequence.
|
||||
bool TrackPanel::HitTestSlide(Track * WXUNUSED(track), const wxRect &rect, const wxMouseEvent & event)
|
||||
{
|
||||
// Perhaps we should delegate this to TrackArtist as only TrackArtist
|
||||
// knows what the real sizes are??
|
||||
|
||||
// The drag Handle width includes border, width and a little extra margin.
|
||||
const int adjustedDragHandleWidth = 14;
|
||||
// The hotspot for the cursor isn't at its centre. Adjust for this.
|
||||
const int hotspotOffset = 5;
|
||||
|
||||
// We are doing an approximate test here - is the mouse in the right or left border?
|
||||
if( event.m_x + hotspotOffset < rect.x + adjustedDragHandleWidth)
|
||||
return true;
|
||||
|
||||
if( event.m_x + hotspotOffset > rect.x + rect.width - adjustedDragHandleWidth)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double TrackPanel::GetMostRecentXPos()
|
||||
{
|
||||
return mViewInfo->PositionToTime(mMouseMostRecentX, GetLabelWidth());
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "SelectedRegion.h"
|
||||
#include "WaveTrackLocation.h"
|
||||
|
||||
#include "Snap.h"
|
||||
#include "Track.h"
|
||||
#include "Snap.h"
|
||||
#include "widgets/OverlayPanel.h"
|
||||
|
||||
#include "SelectionState.h"
|
||||
@ -33,6 +33,8 @@ class wxRect;
|
||||
class EnvelopeEditor;
|
||||
class LabelTrack;
|
||||
class SpectrumAnalyst;
|
||||
class Track;
|
||||
class TrackList;
|
||||
class TrackPanel;
|
||||
class TrackPanelCell;
|
||||
class TrackArtist;
|
||||
@ -49,6 +51,7 @@ class TrackPanelAx;
|
||||
|
||||
class ViewInfo;
|
||||
|
||||
class NoteTrack;
|
||||
class WaveTrack;
|
||||
class WaveClip;
|
||||
class Envelope;
|
||||
@ -254,7 +257,9 @@ const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
||||
|
||||
|
||||
struct ClipMoveState {
|
||||
// non-NULL only if click was in a WaveTrack and without Shift key:
|
||||
WaveClip *capturedClip {};
|
||||
|
||||
bool capturedClipIsSelection {};
|
||||
TrackArray trackExclusions {};
|
||||
double hSlideAmount {};
|
||||
@ -398,7 +403,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
||||
// Working out where to dispatch the event to.
|
||||
virtual int DetermineToolToUse( ToolsToolBar * pTtb, const wxMouseEvent & event);
|
||||
virtual bool HitTestEnvelope(Track *track, const wxRect &rect, const wxMouseEvent & event);
|
||||
virtual bool HitTestSlide(Track *track, const wxRect &rect, const wxMouseEvent & event);
|
||||
#ifdef USE_MIDI
|
||||
// data for NoteTrack interactive stretch operations:
|
||||
// Stretching applies to a selected region after quantizing the
|
||||
@ -499,10 +503,7 @@ protected:
|
||||
virtual void ForwardEventToWaveTrackEnvelope(wxMouseEvent & event);
|
||||
virtual void ForwardEventToEnvelope(wxMouseEvent &event);
|
||||
|
||||
// AS: Track sliding handlers
|
||||
virtual void HandleSlide(wxMouseEvent & event);
|
||||
virtual void StartSlide(wxMouseEvent &event);
|
||||
virtual void DoSlide(wxMouseEvent &event);
|
||||
public:
|
||||
static void DoSlideHorizontal
|
||||
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack );
|
||||
static void CreateListOfCapturedClips
|
||||
@ -514,6 +515,7 @@ protected:
|
||||
static void AddClipsToCaptured
|
||||
( ClipMoveState &state, Track *t, double t0, double t1 );
|
||||
|
||||
protected:
|
||||
static bool IsDragZooming(int zoomStart, int zoomEnd);
|
||||
virtual bool IsDragZooming() { return IsDragZooming(mZoomStart, mZoomEnd); }
|
||||
|
||||
@ -767,18 +769,14 @@ protected:
|
||||
|
||||
Track *mCapturedTrack;
|
||||
Envelope *mCapturedEnvelope;
|
||||
ClipMoveState mClipMoveState;
|
||||
WaveTrackLocation mCapturedTrackLocation;
|
||||
wxRect mCapturedTrackLocationRect;
|
||||
wxRect mCapturedRect;
|
||||
|
||||
bool mDidSlideVertically;
|
||||
|
||||
bool mRedrawAfterStop;
|
||||
|
||||
wxMouseEvent mLastMouseEvent;
|
||||
|
||||
int mMouseClickX;
|
||||
int mMouseClickY;
|
||||
|
||||
int mMouseMostRecentX;
|
||||
@ -792,23 +790,17 @@ protected:
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
// guidelines so the user knows when such snapping is taking place.
|
||||
std::unique_ptr<SnapManager> mSnapManager;
|
||||
|
||||
wxInt64 mSnapLeft { -1 };
|
||||
wxInt64 mSnapRight { -1 };
|
||||
bool mSnapPreferRightEdge;
|
||||
|
||||
public:
|
||||
wxInt64 GetSnapLeft () const
|
||||
{
|
||||
if ( mMouseCapture == IsSliding )
|
||||
return mClipMoveState.snapLeft ;
|
||||
else
|
||||
return mSnapLeft ;
|
||||
}
|
||||
wxInt64 GetSnapRight() const
|
||||
{
|
||||
if ( mMouseCapture == IsSliding )
|
||||
return mClipMoveState.snapRight;
|
||||
else
|
||||
return mSnapRight;
|
||||
}
|
||||
|
||||
@ -869,7 +861,6 @@ public:
|
||||
IsResizingBetweenLinkedTracks,
|
||||
IsResizingBelowLinkedTracks,
|
||||
IsRearranging,
|
||||
IsSliding,
|
||||
IsEnveloping,
|
||||
IsMuting,
|
||||
IsSoloing,
|
||||
@ -888,8 +879,6 @@ protected:
|
||||
enum MouseCaptureEnum mMouseCapture;
|
||||
virtual void SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture=IsUncaptured );
|
||||
|
||||
bool mSlideUpDownOnly;
|
||||
|
||||
// JH: if the user is dragging a track, at what y
|
||||
// coordinate should the dragging track move up or down?
|
||||
int mMoveUpThreshold;
|
||||
@ -898,7 +887,7 @@ protected:
|
||||
|
||||
std::unique_ptr<wxCursor>
|
||||
mArrowCursor, mSelectCursor,
|
||||
mResizeCursor, mSlideCursor, mEnvelopeCursor, // doubles as the center frequency cursor
|
||||
mResizeCursor, mEnvelopeCursor, // doubles as the center frequency cursor
|
||||
// for spectral selection
|
||||
mZoomInCursor, mZoomOutCursor,
|
||||
mRearrangeCursor,
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <wx/access.h>
|
||||
#endif
|
||||
|
||||
#include "Snap.h"
|
||||
#include "Track.h"
|
||||
#include "TrackPanel.h"
|
||||
|
||||
class TrackPanelAx final
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "../Project.h"
|
||||
#include "../ShuttleGui.h"
|
||||
#include "../WaveTrack.h"
|
||||
#include "../Snap.h"
|
||||
|
||||
#include "../TrackPanel.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -21,6 +21,8 @@ Paul Licameli
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "../Project.h"
|
||||
#include "../Snap.h"
|
||||
|
||||
#include "../TrackPanel.h"
|
||||
#include "../ShuttleGui.h"
|
||||
#include "../WaveTrack.h"
|
||||
|
@ -102,7 +102,11 @@ ToolsToolBar::ToolsToolBar()
|
||||
mMessageOfTool[zoomTool] = _("Left=Zoom In, Right=Zoom Out, Middle=Normal");
|
||||
#endif
|
||||
|
||||
// TODO: Should it say "track or clip" ? Non-wave tracks can move, or clips in a wave track.
|
||||
// TODO: mention effects of shift (move all clips of selected wave track) and ctrl (move vertically only) ?
|
||||
// -- but not all of that is available in multi tool.
|
||||
mMessageOfTool[slideTool] = _("Click and drag to move a track in time");
|
||||
|
||||
mMessageOfTool[multiTool] = wxT(""); // multi-mode tool
|
||||
|
||||
bool multiToolActive = false;
|
||||
|
@ -18,6 +18,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../../../toolbars/ToolsToolBar.h"
|
||||
|
||||
#include "SampleHandle.h"
|
||||
#include "../../../ui/TimeShiftHandle.h"
|
||||
|
||||
HitTestResult WaveTrack::HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
@ -29,7 +30,14 @@ HitTestResult WaveTrack::HitTest
|
||||
|
||||
const ToolsToolBar *const pTtb = pProject->GetToolsToolBar();
|
||||
if (pTtb->IsDown(multiTool)) {
|
||||
if (NULL != (result =
|
||||
// Replicate some of the logic of TrackPanel::DetermineToolToUse
|
||||
int currentTool = -1;
|
||||
if (event.event.CmdDown())
|
||||
result = TimeShiftHandle::HitAnywhere(pProject);
|
||||
else if (NULL != (result =
|
||||
TimeShiftHandle::HitTest(event.event, event.rect, pProject)).preview.cursor)
|
||||
;
|
||||
else if (NULL != (result =
|
||||
SampleHandle::HitTest(event.event, event.rect, pProject, this)).preview.cursor)
|
||||
;
|
||||
}
|
||||
|
570
src/tracks/ui/TimeShiftHandle.cpp
Normal file
570
src/tracks/ui/TimeShiftHandle.cpp
Normal file
@ -0,0 +1,570 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
TimeShiftHandle.cpp
|
||||
|
||||
Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../Audacity.h"
|
||||
#include "TimeShiftHandle.h"
|
||||
|
||||
#include "TrackControls.h"
|
||||
#include "../../AColor.h"
|
||||
#include "../../HitTestResult.h"
|
||||
#include "../../Project.h"
|
||||
#include "../../RefreshCode.h"
|
||||
#include "../../Snap.h"
|
||||
#include "../../TrackPanelMouseEvent.h"
|
||||
#include "../../toolbars/ToolsToolBar.h"
|
||||
#include "../../UndoManager.h"
|
||||
#include "../../WaveTrack.h"
|
||||
#include "../../../images/Cursors.h"
|
||||
|
||||
TimeShiftHandle::TimeShiftHandle()
|
||||
{
|
||||
}
|
||||
|
||||
TimeShiftHandle &TimeShiftHandle::Instance()
|
||||
{
|
||||
static TimeShiftHandle instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
HitTestPreview TimeShiftHandle::HitPreview
|
||||
(const AudacityProject *pProject, bool unsafe)
|
||||
{
|
||||
static auto disabledCursor =
|
||||
::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
|
||||
static auto slideCursor =
|
||||
MakeCursor(wxCURSOR_SIZEWE, TimeCursorXpm, 16, 16);
|
||||
const ToolsToolBar *const ttb = pProject->GetToolsToolBar();
|
||||
return {
|
||||
ttb->GetMessageForTool(slideTool),
|
||||
(unsafe
|
||||
? &*disabledCursor
|
||||
: &*slideCursor)
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult TimeShiftHandle::HitAnywhere(const AudacityProject *pProject)
|
||||
{
|
||||
// After all that, it still may be unsafe to drag.
|
||||
// Even if so, make an informative cursor change from default to "banned."
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
return {
|
||||
HitPreview(pProject, unsafe),
|
||||
(unsafe
|
||||
? NULL
|
||||
: &Instance())
|
||||
};
|
||||
}
|
||||
|
||||
HitTestResult TimeShiftHandle::HitTest
|
||||
(const wxMouseEvent & event, const wxRect &rect, const AudacityProject *pProject)
|
||||
{
|
||||
/// method that tells us if the mouse event landed on a
|
||||
/// time-slider that allows us to time shift the sequence.
|
||||
/// (Those are the two "grips" drawn at left and right edges for multi tool mode.)
|
||||
|
||||
// Perhaps we should delegate this to TrackArtist as only TrackArtist
|
||||
// knows what the real sizes are??
|
||||
|
||||
// The drag Handle width includes border, width and a little extra margin.
|
||||
const int adjustedDragHandleWidth = 14;
|
||||
// The hotspot for the cursor isn't at its centre. Adjust for this.
|
||||
const int hotspotOffset = 5;
|
||||
|
||||
// We are doing an approximate test here - is the mouse in the right or left border?
|
||||
if (!(event.m_x + hotspotOffset < rect.x + adjustedDragHandleWidth ||
|
||||
event.m_x + hotspotOffset >= rect.x + rect.width - adjustedDragHandleWidth))
|
||||
return {};
|
||||
|
||||
return HitAnywhere(pProject);
|
||||
}
|
||||
|
||||
TimeShiftHandle::~TimeShiftHandle()
|
||||
{
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Don't count right channels.
|
||||
WaveTrack *NthAudioTrack(TrackList &list, int nn)
|
||||
{
|
||||
if (nn >= 0) {
|
||||
TrackListOfKindIterator iter(Track::Wave, &list);
|
||||
Track *pTrack = iter.First();
|
||||
while (pTrack && nn--)
|
||||
pTrack = iter.Next(true);
|
||||
return static_cast<WaveTrack*>(pTrack);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Don't count right channels.
|
||||
int TrackPosition(TrackList &list, Track *pFindTrack)
|
||||
{
|
||||
Track *const partner = pFindTrack->GetLink();
|
||||
TrackListOfKindIterator iter(Track::Wave, &list);
|
||||
int nn = 0;
|
||||
for (Track *pTrack = iter.First(); pTrack; pTrack = iter.Next(true), ++nn) {
|
||||
if (pTrack == pFindTrack ||
|
||||
pTrack == partner)
|
||||
return nn;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
UIHandle::Result TimeShiftHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
const wxMouseEvent &event = evt.event;
|
||||
const wxRect &rect = evt.rect;
|
||||
const ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
|
||||
Track *const pTrack = static_cast<Track*>(evt.pCell);
|
||||
|
||||
using namespace RefreshCode;
|
||||
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (unsafe)
|
||||
return Cancelled;
|
||||
|
||||
TrackList *const trackList = pProject->GetTracks();
|
||||
|
||||
mClipMoveState.clear();
|
||||
mDidSlideVertically = false;
|
||||
|
||||
ToolsToolBar *const ttb = pProject->GetToolsToolBar();
|
||||
const bool multiToolModeActive = (ttb && ttb->IsDown(multiTool));
|
||||
|
||||
const double clickTime =
|
||||
viewInfo.PositionToTime(event.m_x, rect.x);
|
||||
mClipMoveState.capturedClipIsSelection =
|
||||
(pTrack->GetSelected() &&
|
||||
clickTime >= viewInfo.selectedRegion.t0() &&
|
||||
clickTime < viewInfo.selectedRegion.t1());
|
||||
|
||||
WaveTrack *wt = pTrack->GetKind() == Track::Wave
|
||||
? static_cast<WaveTrack*>(pTrack) : nullptr;
|
||||
|
||||
if ((wt
|
||||
#ifdef USE_MIDI
|
||||
|| pTrack->GetKind() == Track::Note
|
||||
#endif
|
||||
) && !event.ShiftDown())
|
||||
{
|
||||
#ifdef USE_MIDI
|
||||
if (!wt)
|
||||
mClipMoveState.capturedClip = nullptr;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mClipMoveState.capturedClip = wt->GetClipAtX(event.m_x);
|
||||
if (mClipMoveState.capturedClip == NULL)
|
||||
return Cancelled;
|
||||
}
|
||||
|
||||
TrackPanel::CreateListOfCapturedClips
|
||||
( mClipMoveState, viewInfo, *pTrack, *trackList,
|
||||
pProject->IsSyncLocked(), clickTime );
|
||||
}
|
||||
else {
|
||||
// Shift was down, or track was not Wave or Note
|
||||
mClipMoveState.capturedClip = NULL;
|
||||
mClipMoveState.capturedClipArray.clear();
|
||||
}
|
||||
|
||||
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
||||
mCapturedTrack = pTrack;
|
||||
mRect = rect;
|
||||
mMouseClickX = event.m_x;
|
||||
const double selStart = viewInfo.PositionToTime(event.m_x, mRect.x);
|
||||
mSnapManager = std::make_unique<SnapManager>(trackList,
|
||||
&viewInfo,
|
||||
&mClipMoveState.capturedClipArray,
|
||||
&mClipMoveState.trackExclusions,
|
||||
true); // don't snap to time
|
||||
mClipMoveState.snapLeft = -1;
|
||||
mClipMoveState.snapRight = -1;
|
||||
mSnapPreferRightEdge =
|
||||
mClipMoveState.capturedClip &&
|
||||
(fabs(selStart - mClipMoveState.capturedClip->GetEndTime()) <
|
||||
fabs(selStart - mClipMoveState.capturedClip->GetStartTime()));
|
||||
|
||||
return RefreshNone;
|
||||
}
|
||||
|
||||
UIHandle::Result TimeShiftHandle::Drag
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
const wxMouseEvent &event = evt.event;
|
||||
ViewInfo &viewInfo = pProject->GetViewInfo();
|
||||
|
||||
// We may switch pTrack to its stereo partner below
|
||||
Track *pTrack = dynamic_cast<Track*>(evt.pCell);
|
||||
|
||||
// Uncommenting this permits drag to continue to work even over the controls area
|
||||
/*
|
||||
pTrack = static_cast<CommonTrackPanelCell*>(evt.pCell)->FindTrack();
|
||||
*/
|
||||
|
||||
if (!pTrack) {
|
||||
// Allow sliding if the pointer is not over any track, but only if x is
|
||||
// within the bounds of the tracks area.
|
||||
if (event.m_x >= mRect.GetX() &&
|
||||
event.m_x < mRect.GetX() + mRect.GetWidth())
|
||||
pTrack = mCapturedTrack;
|
||||
}
|
||||
|
||||
if (!pTrack)
|
||||
return RefreshCode::RefreshNone;
|
||||
|
||||
using namespace RefreshCode;
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (unsafe) {
|
||||
this->Cancel(pProject);
|
||||
return RefreshAll | Cancelled;
|
||||
}
|
||||
|
||||
TrackList *const trackList = pProject->GetTracks();
|
||||
|
||||
// GM: DoSlide now implementing snap-to
|
||||
// samples functionality based on sample rate.
|
||||
|
||||
// Start by undoing the current slide amount; everything
|
||||
// happens relative to the original horizontal position of
|
||||
// each clip...
|
||||
#ifdef USE_MIDI
|
||||
if (mClipMoveState.capturedClipArray.size())
|
||||
#else
|
||||
if (mClipMoveState.capturedClip)
|
||||
#endif
|
||||
{
|
||||
for (unsigned ii = 0; ii < mClipMoveState.capturedClipArray.size(); ++ii) {
|
||||
if (mClipMoveState.capturedClipArray[ii].clip)
|
||||
mClipMoveState.capturedClipArray[ii].clip->Offset
|
||||
( -mClipMoveState.hSlideAmount );
|
||||
else
|
||||
mClipMoveState.capturedClipArray[ii].track->Offset
|
||||
( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Was a shift-click
|
||||
mCapturedTrack->Offset( -mClipMoveState.hSlideAmount );
|
||||
Track *const link = mCapturedTrack->GetLink();
|
||||
if (link)
|
||||
link->Offset( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
|
||||
if ( mClipMoveState.capturedClipIsSelection ) {
|
||||
// Slide the selection, too
|
||||
viewInfo.selectedRegion.move( -mClipMoveState.hSlideAmount );
|
||||
}
|
||||
mClipMoveState.hSlideAmount = 0.0;
|
||||
|
||||
double desiredSlideAmount;
|
||||
if (mSlideUpDownOnly) {
|
||||
desiredSlideAmount = 0.0;
|
||||
}
|
||||
else {
|
||||
desiredSlideAmount =
|
||||
viewInfo.PositionToTime(event.m_x) -
|
||||
viewInfo.PositionToTime(mMouseClickX);
|
||||
bool trySnap = false;
|
||||
double clipLeft = 0, clipRight = 0;
|
||||
#ifdef USE_MIDI
|
||||
if (pTrack->GetKind() == Track::Wave) {
|
||||
WaveTrack *const mtw = static_cast<WaveTrack*>(pTrack);
|
||||
const double rate = mtw->GetRate();
|
||||
// set it to a sample point
|
||||
desiredSlideAmount = rint(desiredSlideAmount * rate) / rate;
|
||||
}
|
||||
|
||||
// Adjust desiredSlideAmount using SnapManager
|
||||
if (mSnapManager.get() && mClipMoveState.capturedClipArray.size()) {
|
||||
trySnap = true;
|
||||
if (mClipMoveState.capturedClip) {
|
||||
clipLeft = mClipMoveState.capturedClip->GetStartTime()
|
||||
+ desiredSlideAmount;
|
||||
clipRight = mClipMoveState.capturedClip->GetEndTime()
|
||||
+ desiredSlideAmount;
|
||||
}
|
||||
else {
|
||||
clipLeft = mCapturedTrack->GetStartTime() + desiredSlideAmount;
|
||||
clipRight = mCapturedTrack->GetEndTime() + desiredSlideAmount;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
trySnap = true;
|
||||
if (pTrack->GetKind() == Track::Wave) {
|
||||
auto wt = static_cast<const WaveTrack *>(pTrack);
|
||||
const double rate = wt->GetRate();
|
||||
// set it to a sample point
|
||||
desiredSlideAmount = rint(desiredSlideAmount * rate) / rate;
|
||||
if (mSnapManager && mClipMoveState.capturedClip) {
|
||||
clipLeft = mClipMoveState.capturedClip->GetStartTime()
|
||||
+ desiredSlideAmount;
|
||||
clipRight = mClipMoveState.capturedClip->GetEndTime()
|
||||
+ desiredSlideAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (trySnap)
|
||||
{
|
||||
double newClipLeft = clipLeft;
|
||||
double newClipRight = clipRight;
|
||||
|
||||
bool dummy1, dummy2;
|
||||
mSnapManager->Snap(mCapturedTrack, clipLeft, false, &newClipLeft,
|
||||
&dummy1, &dummy2);
|
||||
mSnapManager->Snap(mCapturedTrack, clipRight, false, &newClipRight,
|
||||
&dummy1, &dummy2);
|
||||
|
||||
// Only one of them is allowed to snap
|
||||
if (newClipLeft != clipLeft && newClipRight != clipRight) {
|
||||
// Un-snap the un-preferred edge
|
||||
if (mSnapPreferRightEdge)
|
||||
newClipLeft = clipLeft;
|
||||
else
|
||||
newClipRight = clipRight;
|
||||
}
|
||||
|
||||
// Take whichever one snapped (if any) and compute the NEW desiredSlideAmount
|
||||
mClipMoveState.snapLeft = -1;
|
||||
mClipMoveState.snapRight = -1;
|
||||
if (newClipLeft != clipLeft) {
|
||||
const double difference = (newClipLeft - clipLeft);
|
||||
desiredSlideAmount += difference;
|
||||
mClipMoveState.snapLeft =
|
||||
viewInfo.TimeToPosition(newClipLeft, mRect.x);
|
||||
}
|
||||
else if (newClipRight != clipRight) {
|
||||
const double difference = (newClipRight - clipRight);
|
||||
desiredSlideAmount += difference;
|
||||
mClipMoveState.snapRight =
|
||||
viewInfo.TimeToPosition(newClipRight, mRect.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll during vertical drag.
|
||||
// EnsureVisible(pTrack); //vvv Gale says this has problems on Linux, per bug 393 thread. Revert for 2.0.2.
|
||||
bool slidVertically = false;
|
||||
|
||||
// If the mouse is over a track that isn't the captured track,
|
||||
// decide which tracks the captured clips should go to.
|
||||
if (mClipMoveState.capturedClip &&
|
||||
pTrack != mCapturedTrack &&
|
||||
pTrack->GetKind() == Track::Wave
|
||||
/* && !mCapturedClipIsSelection*/)
|
||||
{
|
||||
const int diff =
|
||||
TrackPosition(*trackList, pTrack) -
|
||||
TrackPosition(*trackList, mCapturedTrack);
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
|
||||
ii < nn; ++ii ) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
if (trackClip.clip) {
|
||||
// Move all clips up or down by an equal count of audio tracks.
|
||||
Track *const pSrcTrack = trackClip.track;
|
||||
auto pDstTrack = NthAudioTrack(*trackList,
|
||||
diff + TrackPosition(*trackList, pSrcTrack));
|
||||
// Can only move mono to mono, or left to left, or right to right
|
||||
// And that must be so for each captured clip
|
||||
bool stereo = (pSrcTrack->GetLink() != 0);
|
||||
if (pDstTrack && stereo && !pSrcTrack->GetLinked())
|
||||
// Assume linked track is wave or null
|
||||
pDstTrack = static_cast<WaveTrack*>(pDstTrack->GetLink());
|
||||
bool ok = pDstTrack &&
|
||||
(stereo == (pDstTrack->GetLink() != 0)) &&
|
||||
(!stereo || (pSrcTrack->GetLinked() == pDstTrack->GetLinked()));
|
||||
if (ok)
|
||||
trackClip.dstTrack = pDstTrack;
|
||||
else
|
||||
return RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
// Having passed that test, remove clips temporarily from their
|
||||
// tracks, so moving clips don't interfere with each other
|
||||
// when we call CanInsertClip()
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
|
||||
ii < nn; ++ii ) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
trackClip.holder =
|
||||
// Assume track is wave because it has a clip
|
||||
static_cast<WaveTrack*>(trackClip.track)->
|
||||
RemoveAndReturnClip(pSrcClip);
|
||||
}
|
||||
|
||||
// Now check that the move is possible
|
||||
bool ok = true;
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
|
||||
ok && ii < nn; ++ii) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
ok = trackClip.dstTrack->CanInsertClip(pSrcClip);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// Failure -- put clips back where they were
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
|
||||
ii < nn; ++ii) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip)
|
||||
// Assume track is wave because it has a clip
|
||||
static_cast<WaveTrack*>(trackClip.track)->
|
||||
AddClip(std::move(trackClip.holder));
|
||||
}
|
||||
return RefreshAll;
|
||||
}
|
||||
else {
|
||||
// Do the vertical moves of clips
|
||||
for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
|
||||
ii < nn; ++ii ) {
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip *const pSrcClip = trackClip.clip;
|
||||
if (pSrcClip) {
|
||||
const auto dstTrack = trackClip.dstTrack;
|
||||
dstTrack->AddClip(std::move(trackClip.holder));
|
||||
trackClip.track = dstTrack;
|
||||
}
|
||||
}
|
||||
|
||||
mCapturedTrack = pTrack;
|
||||
mDidSlideVertically = true;
|
||||
|
||||
// Make the offset permanent; start from a "clean slate"
|
||||
mMouseClickX = event.m_x;
|
||||
}
|
||||
|
||||
// Not done yet, check for horizontal movement.
|
||||
slidVertically = true;
|
||||
}
|
||||
|
||||
if (desiredSlideAmount == 0.0)
|
||||
return RefreshAll;
|
||||
|
||||
mClipMoveState.hSlideAmount = desiredSlideAmount;
|
||||
|
||||
TrackPanel::DoSlideHorizontal( mClipMoveState, *trackList, *mCapturedTrack );
|
||||
|
||||
if (mClipMoveState.capturedClipIsSelection) {
|
||||
// Slide the selection, too
|
||||
viewInfo.selectedRegion.move( mClipMoveState.hSlideAmount );
|
||||
}
|
||||
|
||||
|
||||
if (slidVertically) {
|
||||
// NEW origin
|
||||
mClipMoveState.hSlideAmount = 0;
|
||||
}
|
||||
|
||||
return RefreshAll;
|
||||
}
|
||||
|
||||
HitTestPreview TimeShiftHandle::Preview
|
||||
(const TrackPanelMouseEvent &, const AudacityProject *pProject)
|
||||
{
|
||||
return HitPreview(pProject, false);
|
||||
}
|
||||
|
||||
UIHandle::Result TimeShiftHandle::Release
|
||||
(const TrackPanelMouseEvent &, AudacityProject *pProject,
|
||||
wxWindow *)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
const bool unsafe = pProject->IsAudioActive();
|
||||
if (unsafe)
|
||||
return this->Cancel(pProject);
|
||||
|
||||
Result result = RefreshNone;
|
||||
|
||||
mCapturedTrack = NULL;
|
||||
mSnapManager.reset(NULL);
|
||||
mClipMoveState.capturedClipArray.clear();
|
||||
|
||||
// Do not draw yellow lines
|
||||
if ( mClipMoveState.snapLeft != -1 || mClipMoveState.snapRight != -1) {
|
||||
mClipMoveState.snapLeft = mClipMoveState.snapRight = -1;
|
||||
result |= RefreshAll;
|
||||
}
|
||||
|
||||
if ( !mDidSlideVertically && mClipMoveState.hSlideAmount == 0 )
|
||||
return result;
|
||||
|
||||
for ( size_t ii = 0; ii < mClipMoveState.capturedClipArray.size(); ++ii )
|
||||
{
|
||||
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
|
||||
WaveClip* pWaveClip = trackClip.clip;
|
||||
// Note that per AddClipsToCaptured(Track *t, double t0, double t1),
|
||||
// in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray,
|
||||
// so we have to check for that any time we're going to deref it.
|
||||
// Previous code did not check it here, and that caused bug 367 crash.
|
||||
if (pWaveClip &&
|
||||
trackClip.track != trackClip.origTrack)
|
||||
{
|
||||
// Now that user has dropped the clip into a different track,
|
||||
// make sure the sample rate matches the destination track (mCapturedTrack).
|
||||
// Assume the clip was dropped in a wave track
|
||||
pWaveClip->Resample
|
||||
(static_cast<WaveTrack*>(trackClip.track)->GetRate());
|
||||
pWaveClip->MarkChanged();
|
||||
}
|
||||
}
|
||||
|
||||
wxString msg;
|
||||
bool consolidate;
|
||||
if (mDidSlideVertically) {
|
||||
msg.Printf(_("Moved clips to another track"));
|
||||
consolidate = false;
|
||||
}
|
||||
else {
|
||||
wxString direction = mClipMoveState.hSlideAmount > 0 ?
|
||||
/* i18n-hint: a direction as in left or right.*/
|
||||
_("right") :
|
||||
/* i18n-hint: a direction as in left or right.*/
|
||||
_("left");
|
||||
/* i18n-hint: %s is a direction like left or right */
|
||||
msg.Printf(_("Time shifted tracks/clips %s %.02f seconds"),
|
||||
direction.c_str(), fabs( mClipMoveState.hSlideAmount ));
|
||||
consolidate = true;
|
||||
}
|
||||
pProject->PushState(msg, _("Time-Shift"),
|
||||
consolidate ? (UndoPush::CONSOLIDATE) : (UndoPush::AUTOSAVE));
|
||||
|
||||
return result | FixScrollbars;
|
||||
}
|
||||
|
||||
UIHandle::Result TimeShiftHandle::Cancel(AudacityProject *pProject)
|
||||
{
|
||||
pProject->RollbackState();
|
||||
mCapturedTrack = nullptr;
|
||||
mSnapManager.reset();
|
||||
mClipMoveState.clear();
|
||||
return RefreshCode::RefreshAll;
|
||||
}
|
||||
|
||||
void TimeShiftHandle::DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &, const wxRect &)
|
||||
{
|
||||
if (pass == Panel) {
|
||||
// Draw snap guidelines if we have any
|
||||
if ( mSnapManager )
|
||||
mSnapManager->Draw
|
||||
( dc, mClipMoveState.snapLeft, mClipMoveState.snapRight );
|
||||
}
|
||||
}
|
84
src/tracks/ui/TimeShiftHandle.h
Normal file
84
src/tracks/ui/TimeShiftHandle.h
Normal file
@ -0,0 +1,84 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
TimeShiftHandle.h
|
||||
|
||||
Paul Licameli
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_TIMESHIFT_HANDLE__
|
||||
#define __AUDACITY_TIMESHIFT_HANDLE__
|
||||
|
||||
#include "../../UIHandle.h"
|
||||
|
||||
#include "../../MemoryX.h"
|
||||
|
||||
#include "../../Snap.h"
|
||||
#include "../../Track.h"
|
||||
|
||||
#include "../../TrackPanel.h" // for ClipMoveState
|
||||
|
||||
struct HitTestResult;
|
||||
class WaveClip;
|
||||
|
||||
class TimeShiftHandle final : public UIHandle
|
||||
{
|
||||
TimeShiftHandle();
|
||||
TimeShiftHandle(const TimeShiftHandle&) = delete;
|
||||
TimeShiftHandle &operator=(const TimeShiftHandle&) = delete;
|
||||
static TimeShiftHandle& Instance();
|
||||
static HitTestPreview HitPreview
|
||||
(const AudacityProject *pProject, bool unsafe);
|
||||
|
||||
public:
|
||||
static HitTestResult HitAnywhere(const AudacityProject *pProject);
|
||||
static HitTestResult HitTest
|
||||
(const wxMouseEvent &event, const wxRect &rect, const AudacityProject *pProject);
|
||||
|
||||
virtual ~TimeShiftHandle();
|
||||
|
||||
Result Click
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
Result Drag
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject) override;
|
||||
|
||||
HitTestPreview Preview
|
||||
(const TrackPanelMouseEvent &event, const AudacityProject *pProject)
|
||||
override;
|
||||
|
||||
Result Release
|
||||
(const TrackPanelMouseEvent &event, AudacityProject *pProject,
|
||||
wxWindow *pParent) override;
|
||||
|
||||
Result Cancel(AudacityProject *pProject) override;
|
||||
|
||||
void DrawExtras
|
||||
(DrawingPass pass,
|
||||
wxDC * dc, const wxRegion &, const wxRect &panelRect) override;
|
||||
|
||||
bool StopsOnKeystroke() override { return true; }
|
||||
|
||||
private:
|
||||
Track *mCapturedTrack{};
|
||||
wxRect mRect{};
|
||||
|
||||
bool mDidSlideVertically{};
|
||||
bool mSlideUpDownOnly{};
|
||||
|
||||
bool mSnapPreferRightEdge{};
|
||||
|
||||
int mMouseClickX{};
|
||||
|
||||
// Handles snapping the selection boundaries or track boundaries to
|
||||
// line up with existing tracks or labels. mSnapLeft and mSnapRight
|
||||
// are the horizontal index of pixels to display user feedback
|
||||
// guidelines so the user knows when such snapping is taking place.
|
||||
std::unique_ptr<SnapManager> mSnapManager{};
|
||||
|
||||
ClipMoveState mClipMoveState{};
|
||||
};
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
#include "../playabletrack/wavetrack/ui/SampleHandle.h"
|
||||
#include "ZoomHandle.h"
|
||||
#include "TimeShiftHandle.h"
|
||||
|
||||
HitTestResult Track::HitTest
|
||||
(const TrackPanelMouseEvent &event,
|
||||
@ -33,10 +34,11 @@ HitTestResult Track::HitTest
|
||||
return SampleHandle::HitAnywhere(event.event, pProject);
|
||||
case zoomTool:
|
||||
return ZoomHandle::HitAnywhere(event.event, pProject);
|
||||
case slideTool:
|
||||
return TimeShiftHandle::HitAnywhere(pProject);
|
||||
|
||||
case selectTool:
|
||||
case envelopeTool:
|
||||
case slideTool:
|
||||
default:
|
||||
// cases not yet implemented
|
||||
// fallthru
|
||||
|
@ -241,6 +241,7 @@
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\EditCursorOverlay.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\PlayIndicatorOverlay.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\Scrubbing.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TimeShiftHandle.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TrackControls.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TrackUI.cpp" />
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TrackVRulerControls.cpp" />
|
||||
@ -503,6 +504,7 @@
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\Scrubbing.h" />
|
||||
<ClInclude Include="..\..\..\src\TranslatableStringArray.h" />
|
||||
<ClInclude Include="..\..\..\src\UserException.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\TimeShiftHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\TrackControls.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\ZoomHandle.h" />
|
||||
<ClInclude Include="..\..\..\src\tracks\timetrack\ui\TimeTrackVRulerControls.h" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
@ -953,6 +953,9 @@
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\ZoomHandle.cpp">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\tracks\ui\TimeShiftHandle.cpp">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\src\tracks\timetrack\ui\TimeTrackControls.cpp">
|
||||
<Filter>src\tracks\timetrack\ui</Filter>
|
||||
</ClCompile>
|
||||
@ -1984,6 +1987,9 @@
|
||||
<ClInclude Include="..\..\..\src\tracks\playabletrack\wavetrack\ui\SampleHandle.h">
|
||||
<Filter>src\tracks\playabletrack\wavetrack\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\tracks\ui\TimeShiftHandle.h">
|
||||
<Filter>src\tracks\ui</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\audacity.ico">
|
||||
|
Loading…
x
Reference in New Issue
Block a user