mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-27 06:07:59 +02:00
Merge branch 'seek-refactor' by Evan Short
- More function calls with cryptic options made clearer.
This commit is contained in:
commit
1ccd2678b6
467
src/Menus.cpp
467
src/Menus.cpp
@ -3129,22 +3129,22 @@ void AudacityProject::OnSkipEnd(const CommandContext &WXUNUSED(context) )
|
|||||||
|
|
||||||
void AudacityProject::OnSeekLeftShort(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSeekLeftShort(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorLeft( false, false );
|
SeekLeftOrRight( DIRECTION_LEFT, CURSOR_MOVE );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSeekRightShort(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSeekRightShort(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorRight( false, false );
|
SeekLeftOrRight( DIRECTION_RIGHT, CURSOR_MOVE );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSeekLeftLong(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSeekLeftLong(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorLeft( true, false );
|
SeekLeftOrRight( DIRECTION_LEFT, SELECTION_EXTEND );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSeekRightLong(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSeekRightLong(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorRight( true, false );
|
SeekLeftOrRight( DIRECTION_RIGHT, SELECTION_EXTEND );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelToStart(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSelToStart(const CommandContext &WXUNUSED(context) )
|
||||||
@ -3532,77 +3532,87 @@ void AudacityProject::HandleListSelection(Track *t, bool shift, bool ctrl,
|
|||||||
ModifyState(true);
|
ModifyState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this returns true, then there was a key up, and nothing more to do,
|
||||||
void AudacityProject::OnCursorLeft(const CommandContext &context)
|
// after this function has completed.
|
||||||
|
// (at most this function just does a ModifyState for the keyup)
|
||||||
|
bool AudacityProject::OnlyHandleKeyUp( const CommandContext &context )
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
auto evt = context.pEvt;
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
||||||
OnCursorLeft( false, false, bKeyUp );
|
|
||||||
|
if( IsAudioActive() )
|
||||||
|
return bKeyUp;
|
||||||
|
if( !bKeyUp )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ModifyState(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudacityProject::OnCursorLeft(const CommandContext &context)
|
||||||
|
{
|
||||||
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
|
SeekLeftOrRight( DIRECTION_LEFT, CURSOR_MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorRight(const CommandContext &context)
|
void AudacityProject::OnCursorRight(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
SeekLeftOrRight( DIRECTION_RIGHT, CURSOR_MOVE);
|
||||||
OnCursorRight( false, false, bKeyUp );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorShortJumpLeft(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnCursorShortJumpLeft(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorMove( false, true, false );
|
OnCursorMove( -mSeekShort );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorShortJumpRight(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnCursorShortJumpRight(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorMove( true, true, false );
|
OnCursorMove( mSeekShort );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorLongJumpLeft(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnCursorLongJumpLeft(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorMove( false, true, true );
|
OnCursorMove( -mSeekLong );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorLongJumpRight(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnCursorLongJumpRight(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnCursorMove( true, true, true );
|
OnCursorMove( mSeekLong );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelSetExtendLeft(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSelSetExtendLeft(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnBoundaryMove( true, false);
|
OnBoundaryMove( DIRECTION_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelSetExtendRight(const CommandContext &WXUNUSED(context) )
|
void AudacityProject::OnSelSetExtendRight(const CommandContext &WXUNUSED(context) )
|
||||||
{
|
{
|
||||||
OnBoundaryMove( false, false);
|
OnBoundaryMove( DIRECTION_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelExtendLeft(const CommandContext &context)
|
void AudacityProject::OnSelExtendLeft(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
SeekLeftOrRight( DIRECTION_LEFT, SELECTION_EXTEND );
|
||||||
OnCursorLeft( true, false, bKeyUp );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelExtendRight(const CommandContext &context)
|
void AudacityProject::OnSelExtendRight(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
SeekLeftOrRight( DIRECTION_RIGHT, SELECTION_EXTEND );
|
||||||
OnCursorRight( true, false, bKeyUp );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelContractLeft(const CommandContext &context)
|
void AudacityProject::OnSelContractLeft(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
SeekLeftOrRight( DIRECTION_LEFT, SELECTION_CONTRACT );
|
||||||
OnCursorRight( true, true, bKeyUp );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnSelContractRight(const CommandContext &context)
|
void AudacityProject::OnSelContractRight(const CommandContext &context)
|
||||||
{
|
{
|
||||||
auto evt = context.pEvt;
|
if( !OnlyHandleKeyUp( context ) )
|
||||||
bool bKeyUp = (evt) && evt->GetEventType() == wxEVT_KEY_UP;
|
SeekLeftOrRight( DIRECTION_RIGHT, SELECTION_CONTRACT );
|
||||||
OnCursorLeft( true, true, bKeyUp );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "tracks/ui/TimeShiftHandle.h"
|
#include "tracks/ui/TimeShiftHandle.h"
|
||||||
@ -9014,51 +9024,22 @@ void AudacityProject::OnFullScreen(const CommandContext &WXUNUSED(context) )
|
|||||||
mCommandManager.Check(wxT("FullScreenOnOff"), bChecked);
|
mCommandManager.Check(wxT("FullScreenOnOff"), bChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnCursorLeft(bool shift, bool ctrl, bool keyup)
|
|
||||||
{
|
|
||||||
// PRL: What I found and preserved, strange though it be:
|
|
||||||
// During playback: jump depends on preferences and is independent of the zoom
|
|
||||||
// and does not vary if the key is held
|
|
||||||
// Else: jump depends on the zoom and gets bigger if the key is held
|
|
||||||
int snapToTime = GetSnapTo();
|
|
||||||
double quietSeekStepPositive = 1.0; // pixels
|
|
||||||
double audioSeekStepPositive = shift ? mSeekLong : mSeekShort;
|
|
||||||
SeekLeftOrRight
|
|
||||||
(true, shift, ctrl, keyup, snapToTime, true, false,
|
|
||||||
quietSeekStepPositive, true,
|
|
||||||
audioSeekStepPositive, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudacityProject::OnCursorRight(bool shift, bool ctrl, bool keyup)
|
|
||||||
{
|
|
||||||
// PRL: What I found and preserved, strange though it be:
|
|
||||||
// During playback: jump depends on preferences and is independent of the zoom
|
|
||||||
// and does not vary if the key is held
|
|
||||||
// Else: jump depends on the zoom and gets bigger if the key is held
|
|
||||||
int snapToTime = GetSnapTo();
|
|
||||||
double quietSeekStepPositive = 1.0; // pixels
|
|
||||||
double audioSeekStepPositive = shift ? mSeekLong : mSeekShort;
|
|
||||||
SeekLeftOrRight
|
|
||||||
(false, shift, ctrl, keyup, snapToTime, true, false,
|
|
||||||
quietSeekStepPositive, true,
|
|
||||||
audioSeekStepPositive, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle small cursor and play head movements
|
// Handle small cursor and play head movements
|
||||||
void AudacityProject::SeekLeftOrRight
|
void AudacityProject::SeekLeftOrRight
|
||||||
(bool leftward, bool shift, bool ctrl, bool keyup,
|
(double direction, SelectionOperation operation)
|
||||||
int snapToTime, bool mayAccelerateQuiet, bool mayAccelerateAudio,
|
|
||||||
double quietSeekStepPositive, bool quietStepIsPixels,
|
|
||||||
double audioSeekStepPositive, bool audioStepIsPixels)
|
|
||||||
{
|
|
||||||
if (keyup)
|
|
||||||
{
|
{
|
||||||
|
// PRL: What I found and preserved, strange though it be:
|
||||||
|
// During playback: jump depends on preferences and is independent of the zoom
|
||||||
|
// and does not vary if the key is held
|
||||||
|
// Else: jump depends on the zoom and gets bigger if the key is held
|
||||||
|
|
||||||
if( IsAudioActive() )
|
if( IsAudioActive() )
|
||||||
{
|
{
|
||||||
return;
|
if( operation == CURSOR_MOVE )
|
||||||
}
|
SeekWhenAudioActive(mSeekShort * direction);
|
||||||
|
else if( operation == SELECTION_EXTEND )
|
||||||
ModifyState(false);
|
SeekWhenAudioActive(mSeekLong * direction);
|
||||||
|
// Note: no action for CURSOR_CONTRACT
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9068,51 +9049,17 @@ void AudacityProject::SeekLeftOrRight
|
|||||||
enum { MIN_INTERVAL = 50 };
|
enum { MIN_INTERVAL = 50 };
|
||||||
const bool fast = (curtime - mLastSelectionAdjustment < MIN_INTERVAL);
|
const bool fast = (curtime - mLastSelectionAdjustment < MIN_INTERVAL);
|
||||||
|
|
||||||
// How much faster should the cursor move if shift is down?
|
|
||||||
enum { LARGER_MULTIPLIER = 4 };
|
|
||||||
int multiplier = (fast && mayAccelerateQuiet) ? LARGER_MULTIPLIER : 1;
|
|
||||||
if (leftward)
|
|
||||||
multiplier = -multiplier;
|
|
||||||
|
|
||||||
if (shift && ctrl)
|
|
||||||
{
|
|
||||||
mLastSelectionAdjustment = curtime;
|
mLastSelectionAdjustment = curtime;
|
||||||
|
|
||||||
// Contract selection
|
// How much faster should the cursor move if shift is down?
|
||||||
// Reduce and constrain (counter-intuitive)
|
enum { LARGER_MULTIPLIER = 4 };
|
||||||
if (leftward) {
|
const double seekStep = (fast ? LARGER_MULTIPLIER : 1.0) * direction;
|
||||||
const double t1 = mViewInfo.selectedRegion.t1();
|
|
||||||
mViewInfo.selectedRegion.setT1(
|
|
||||||
std::max(mViewInfo.selectedRegion.t0(),
|
|
||||||
snapToTime
|
|
||||||
? GridMove(t1, multiplier)
|
|
||||||
: quietStepIsPixels
|
|
||||||
? mViewInfo.OffsetTimeByPixels(
|
|
||||||
t1, (int)(multiplier * quietSeekStepPositive))
|
|
||||||
: t1 + multiplier * quietSeekStepPositive
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure it's visible.
|
SeekWhenAudioInactive( seekStep, TIME_UNIT_PIXELS, operation);
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
const double t0 = mViewInfo.selectedRegion.t0();
|
|
||||||
mViewInfo.selectedRegion.setT0(
|
|
||||||
std::min(mViewInfo.selectedRegion.t1(),
|
|
||||||
snapToTime
|
|
||||||
? GridMove(t0, multiplier)
|
|
||||||
: quietStepIsPixels
|
|
||||||
? mViewInfo.OffsetTimeByPixels(
|
|
||||||
t0, (int)(multiplier * quietSeekStepPositive))
|
|
||||||
: t0 + multiplier * quietSeekStepPositive
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure NEW position is in view.
|
void AudacityProject::SeekWhenAudioActive(double seekStep)
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
{
|
||||||
}
|
|
||||||
GetTrackPanel()->Refresh(false);
|
|
||||||
}
|
|
||||||
else if (IsAudioActive()) {
|
|
||||||
#ifdef EXPERIMENTAL_IMPROVED_SEEKING
|
#ifdef EXPERIMENTAL_IMPROVED_SEEKING
|
||||||
if (gAudioIO->GetLastPlaybackTime() < mLastSelectionAdjustment) {
|
if (gAudioIO->GetLastPlaybackTime() < mLastSelectionAdjustment) {
|
||||||
// Allow time for the last seek to output a buffer before
|
// Allow time for the last seek to output a buffer before
|
||||||
@ -9121,87 +9068,128 @@ void AudacityProject::SeekLeftOrRight
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
mLastSelectionAdjustment = ::wxGetLocalTimeMillis();
|
||||||
|
|
||||||
|
gAudioIO->SeekStream(seekStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudacityProject::OnBoundaryMove(int step)
|
||||||
|
{
|
||||||
|
// step is negative, then is moving left. step positive, moving right.
|
||||||
|
// Move the left/right selection boundary, to expand the selection
|
||||||
|
|
||||||
|
// If the last adjustment was very recent, we are
|
||||||
|
// holding the key down and should move faster.
|
||||||
|
wxLongLong curtime = ::wxGetLocalTimeMillis();
|
||||||
|
int pixels = step;
|
||||||
|
if( curtime - mLastSelectionAdjustment < 50 )
|
||||||
|
{
|
||||||
|
pixels *= 4;
|
||||||
|
}
|
||||||
mLastSelectionAdjustment = curtime;
|
mLastSelectionAdjustment = curtime;
|
||||||
|
|
||||||
// Ignore the multiplier for the quiet case
|
// we used to have a parameter boundaryContract to say if expanding or contracting.
|
||||||
multiplier = (fast && mayAccelerateAudio) ? LARGER_MULTIPLIER : 1;
|
// it is no longer needed.
|
||||||
if (leftward)
|
bool bMoveT0 = (step < 0 );// ^ boundaryContract ;
|
||||||
multiplier = -multiplier;
|
|
||||||
|
|
||||||
// If playing, reposition
|
if( IsAudioActive() )
|
||||||
double seconds;
|
{
|
||||||
if (audioStepIsPixels) {
|
double indicator = gAudioIO->GetStreamTime();
|
||||||
const double streamTime = gAudioIO->GetStreamTime();
|
if( bMoveT0 )
|
||||||
const double newTime =
|
mViewInfo.selectedRegion.setT0(indicator, false);
|
||||||
mViewInfo.OffsetTimeByPixels(streamTime, (int)(audioSeekStepPositive));
|
|
||||||
seconds = newTime - streamTime;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
seconds = multiplier * audioSeekStepPositive;
|
mViewInfo.selectedRegion.setT1(indicator);
|
||||||
gAudioIO->SeekStream(seconds);
|
|
||||||
|
ModifyState(false);
|
||||||
|
GetTrackPanel()->Refresh(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (shift)
|
|
||||||
{
|
|
||||||
mLastSelectionAdjustment = curtime;
|
|
||||||
|
|
||||||
// Extend selection
|
|
||||||
// Expand and constrain
|
|
||||||
if (leftward) {
|
|
||||||
const double t0 = mViewInfo.selectedRegion.t0();
|
const double t0 = mViewInfo.selectedRegion.t0();
|
||||||
mViewInfo.selectedRegion.setT0(
|
|
||||||
std::max(0.0,
|
|
||||||
snapToTime
|
|
||||||
? GridMove(t0, multiplier)
|
|
||||||
: quietStepIsPixels
|
|
||||||
? mViewInfo.OffsetTimeByPixels(
|
|
||||||
t0, (int)(multiplier * quietSeekStepPositive))
|
|
||||||
: t0 + multiplier * quietSeekStepPositive
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure it's visible.
|
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const double end = mTracks->GetEndTime();
|
|
||||||
const double t1 = mViewInfo.selectedRegion.t1();
|
const double t1 = mViewInfo.selectedRegion.t1();
|
||||||
mViewInfo.selectedRegion.setT1(
|
const double end = mTracks->GetEndTime();
|
||||||
std::min(end,
|
|
||||||
snapToTime
|
|
||||||
? GridMove(t1, multiplier)
|
|
||||||
: quietStepIsPixels
|
|
||||||
? mViewInfo.OffsetTimeByPixels(
|
|
||||||
t1, (int)(multiplier * quietSeekStepPositive))
|
|
||||||
: t1 + multiplier * quietSeekStepPositive
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure NEW position is in view.
|
double newT = mViewInfo.OffsetTimeByPixels( bMoveT0 ? t0 : t1, pixels);
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
// constrain to be in the track limits.
|
||||||
|
newT = std::max( 0.0, newT );
|
||||||
|
newT = std::min( newT, end);
|
||||||
|
// optionally constrain to be a contraction, i.e. so t0/t1 do not cross over
|
||||||
|
//if( boundaryContract )
|
||||||
|
// newT = bMoveT0 ? std::min( t1, newT ) : std::max( t0, newT );
|
||||||
|
|
||||||
|
// Actually move
|
||||||
|
if( bMoveT0 )
|
||||||
|
mViewInfo.selectedRegion.setT0( newT );
|
||||||
|
else
|
||||||
|
mViewInfo.selectedRegion.setT1( newT );
|
||||||
|
|
||||||
|
// Ensure it is visible, and refresh.
|
||||||
|
GetTrackPanel()->ScrollIntoView(newT);
|
||||||
|
GetTrackPanel()->Refresh(false);
|
||||||
|
|
||||||
|
ModifyState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudacityProject::SeekWhenAudioInactive
|
||||||
|
(double seekStep, TimeUnit timeUnit,
|
||||||
|
SelectionOperation operation)
|
||||||
|
{
|
||||||
|
if( operation == CURSOR_MOVE )
|
||||||
|
{
|
||||||
|
MoveWhenAudioInactive( seekStep, timeUnit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snapToTime = GetSnapTo();
|
||||||
|
const double t0 = mViewInfo.selectedRegion.t0();
|
||||||
|
const double t1 = mViewInfo.selectedRegion.t1();
|
||||||
|
const double end = mTracks->GetEndTime();
|
||||||
|
|
||||||
|
// Is it t0 or t1 moving?
|
||||||
|
bool bMoveT0 = ( operation == SELECTION_CONTRACT ) ^ ( seekStep < 0 );
|
||||||
|
// newT is where we want to move to
|
||||||
|
double newT = OffsetTime( bMoveT0 ? t0 : t1, seekStep, timeUnit, snapToTime);
|
||||||
|
// constrain to be in the track limits.
|
||||||
|
newT = std::max( 0.0, newT );
|
||||||
|
newT = std::min( newT, end);
|
||||||
|
// optionally constrain to be a contraction, i.e. so t0/t1 do not cross over
|
||||||
|
if( operation == SELECTION_CONTRACT )
|
||||||
|
newT = bMoveT0 ? std::min( t1, newT ) : std::max( t0, newT );
|
||||||
|
|
||||||
|
// Actually move
|
||||||
|
if( bMoveT0 )
|
||||||
|
mViewInfo.selectedRegion.setT0( newT );
|
||||||
|
else
|
||||||
|
mViewInfo.selectedRegion.setT1( newT );
|
||||||
|
|
||||||
|
// Ensure it is visible, and refresh.
|
||||||
|
GetTrackPanel()->ScrollIntoView(newT);
|
||||||
GetTrackPanel()->Refresh(false);
|
GetTrackPanel()->Refresh(false);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Moving a cursor, and collapsed selection.
|
||||||
|
void AudacityProject::MoveWhenAudioInactive
|
||||||
|
(double seekStep, TimeUnit timeUnit)
|
||||||
{
|
{
|
||||||
mLastSelectionAdjustment = curtime;
|
// If TIME_UNIT_SECONDS, snap-to will be off.
|
||||||
|
int snapToTime = GetSnapTo();
|
||||||
|
const double t0 = mViewInfo.selectedRegion.t0();
|
||||||
|
const double t1 = mViewInfo.selectedRegion.t1();
|
||||||
|
const double end = mTracks->GetEndTime();
|
||||||
|
|
||||||
// Move the cursor
|
// Move the cursor
|
||||||
// Already in cursor mode?
|
// Already in cursor mode?
|
||||||
if( mViewInfo.selectedRegion.isPoint() )
|
if( mViewInfo.selectedRegion.isPoint() )
|
||||||
{
|
{
|
||||||
// Move and constrain
|
double newT = OffsetTime(t0, seekStep, timeUnit, snapToTime);
|
||||||
const double end = mTracks->GetEndTime();
|
// constrain.
|
||||||
const double t0 = mViewInfo.selectedRegion.t0();
|
newT = std::max(0.0, newT);
|
||||||
|
newT = std::min(newT, end);
|
||||||
|
// Move
|
||||||
mViewInfo.selectedRegion.setT0(
|
mViewInfo.selectedRegion.setT0(
|
||||||
std::max(0.0,
|
newT,
|
||||||
std::min(end,
|
false); // do not swap selection boundaries
|
||||||
snapToTime
|
|
||||||
? GridMove(t0, multiplier)
|
|
||||||
: quietStepIsPixels
|
|
||||||
? mViewInfo.OffsetTimeByPixels(
|
|
||||||
t0, (int)(multiplier * quietSeekStepPositive))
|
|
||||||
: t0 + multiplier * quietSeekStepPositive)),
|
|
||||||
false // do not swap selection boundaries
|
|
||||||
);
|
|
||||||
mViewInfo.selectedRegion.collapseToT0();
|
mViewInfo.selectedRegion.collapseToT0();
|
||||||
|
|
||||||
// Move the visual cursor, avoiding an unnecessary complete redraw
|
// Move the visual cursor, avoiding an unnecessary complete redraw
|
||||||
@ -9210,11 +9198,10 @@ void AudacityProject::SeekLeftOrRight
|
|||||||
|
|
||||||
// This updates the selection shown on the selection bar, and the play region
|
// This updates the selection shown on the selection bar, and the play region
|
||||||
TP_DisplaySelection();
|
TP_DisplaySelection();
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Transition to cursor mode.
|
// Transition to cursor mode.
|
||||||
if (leftward)
|
if( seekStep < 0 )
|
||||||
mViewInfo.selectedRegion.collapseToT0();
|
mViewInfo.selectedRegion.collapseToT0();
|
||||||
else
|
else
|
||||||
mViewInfo.selectedRegion.collapseToT1();
|
mViewInfo.selectedRegion.collapseToT1();
|
||||||
@ -9223,7 +9210,19 @@ void AudacityProject::SeekLeftOrRight
|
|||||||
|
|
||||||
// Make sure NEW position is in view
|
// Make sure NEW position is in view
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double AudacityProject::OffsetTime
|
||||||
|
(double t, double offset, TimeUnit timeUnit, int snapToTime)
|
||||||
|
{
|
||||||
|
if (timeUnit == TIME_UNIT_SECONDS)
|
||||||
|
return t + offset; // snapping is currently ignored for non-pixel moves
|
||||||
|
|
||||||
|
if (snapToTime == SNAP_OFF)
|
||||||
|
return mViewInfo.OffsetTimeByPixels(t, (int)offset);
|
||||||
|
|
||||||
|
return GridMove(t, (int)offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles moving a selection edge with the keyboard in snap-to-time mode;
|
// Handles moving a selection edge with the keyboard in snap-to-time mode;
|
||||||
@ -9250,128 +9249,18 @@ double AudacityProject::GridMove(double t, int minPix)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityProject::OnBoundaryMove(bool left, bool boundaryContract)
|
|
||||||
{
|
|
||||||
// Move the left/right selection boundary, to either expand or contract the selection
|
|
||||||
// left=true: operate on left boundary; left=false: operate on right boundary
|
|
||||||
// boundaryContract=true: contract region; boundaryContract=false: expand region.
|
|
||||||
|
|
||||||
// If the last adjustment was very recent, we are
|
|
||||||
// holding the key down and should move faster.
|
|
||||||
wxLongLong curtime = ::wxGetLocalTimeMillis();
|
|
||||||
int pixels = 1;
|
|
||||||
if( curtime - mLastSelectionAdjustment < 50 )
|
|
||||||
{
|
|
||||||
pixels = 4;
|
|
||||||
}
|
|
||||||
mLastSelectionAdjustment = curtime;
|
|
||||||
|
|
||||||
if (IsAudioActive())
|
|
||||||
{
|
|
||||||
double indicator = gAudioIO->GetStreamTime();
|
|
||||||
if (left)
|
|
||||||
mViewInfo.selectedRegion.setT0(indicator, false);
|
|
||||||
else
|
|
||||||
mViewInfo.selectedRegion.setT1(indicator);
|
|
||||||
|
|
||||||
ModifyState(false);
|
|
||||||
GetTrackPanel()->Refresh(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// BOUNDARY MOVEMENT
|
|
||||||
// Contract selection from the right to the left
|
|
||||||
if( boundaryContract )
|
|
||||||
{
|
|
||||||
if (left) {
|
|
||||||
// Reduce and constrain left boundary (counter-intuitive)
|
|
||||||
// Move the left boundary by at most the desired number of pixels,
|
|
||||||
// but not past the right
|
|
||||||
mViewInfo.selectedRegion.setT0(
|
|
||||||
std::min(mViewInfo.selectedRegion.t1(),
|
|
||||||
mViewInfo.OffsetTimeByPixels(
|
|
||||||
mViewInfo.selectedRegion.t0(),
|
|
||||||
pixels)));
|
|
||||||
|
|
||||||
// Make sure it's visible
|
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Reduce and constrain right boundary (counter-intuitive)
|
|
||||||
// Move the right boundary by at most the desired number of pixels,
|
|
||||||
// but not past the left
|
|
||||||
mViewInfo.selectedRegion.setT1(
|
|
||||||
std::max(mViewInfo.selectedRegion.t0(),
|
|
||||||
mViewInfo.OffsetTimeByPixels(
|
|
||||||
mViewInfo.selectedRegion.t1(),
|
|
||||||
-pixels)));
|
|
||||||
|
|
||||||
// Make sure it's visible
|
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// BOUNDARY MOVEMENT
|
|
||||||
// Extend selection toward the left
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (left) {
|
|
||||||
// Expand and constrain left boundary
|
|
||||||
mViewInfo.selectedRegion.setT0(
|
|
||||||
std::max(0.0,
|
|
||||||
mViewInfo.OffsetTimeByPixels(
|
|
||||||
mViewInfo.selectedRegion.t0(),
|
|
||||||
-pixels)));
|
|
||||||
|
|
||||||
// Make sure it's visible
|
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t0());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Expand and constrain right boundary
|
|
||||||
const double end = mTracks->GetEndTime();
|
|
||||||
mViewInfo.selectedRegion.setT1(
|
|
||||||
std::min(end,
|
|
||||||
mViewInfo.OffsetTimeByPixels(
|
|
||||||
mViewInfo.selectedRegion.t1(),
|
|
||||||
pixels)));
|
|
||||||
|
|
||||||
// Make sure it's visible
|
|
||||||
GetTrackPanel()->ScrollIntoView(mViewInfo.selectedRegion.t1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GetTrackPanel()->Refresh( false );
|
|
||||||
ModifyState(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the cursor forward or backward, while paused or while playing.
|
// Move the cursor forward or backward, while paused or while playing.
|
||||||
// forward=true: Move cursor forward; forward=false: Move cursor backwards
|
void AudacityProject::OnCursorMove(double seekStep)
|
||||||
// jump=false: Move cursor determined by zoom; jump=true: Use seek times
|
|
||||||
// longjump=false: Use mSeekShort; longjump=true: Use mSeekLong
|
|
||||||
void AudacityProject::OnCursorMove(bool forward, bool jump, bool longjump )
|
|
||||||
{
|
{
|
||||||
// PRL: nobody calls this yet with !jump
|
if (IsAudioActive()) {
|
||||||
|
SeekWhenAudioActive(seekStep);
|
||||||
double positiveSeekStep;
|
|
||||||
bool byPixels;
|
|
||||||
if (jump) {
|
|
||||||
if (!longjump) {
|
|
||||||
positiveSeekStep = mSeekShort;
|
|
||||||
} else {
|
|
||||||
positiveSeekStep = mSeekLong;
|
|
||||||
}
|
}
|
||||||
byPixels = false;
|
else
|
||||||
} else {
|
{
|
||||||
positiveSeekStep = 1.0;
|
mLastSelectionAdjustment = ::wxGetLocalTimeMillis();
|
||||||
byPixels = true;
|
MoveWhenAudioInactive(seekStep, TIME_UNIT_SECONDS);
|
||||||
}
|
}
|
||||||
bool mayAccelerate = !jump;
|
|
||||||
SeekLeftOrRight
|
|
||||||
(!forward, false, false, false,
|
|
||||||
0, mayAccelerate, mayAccelerate,
|
|
||||||
positiveSeekStep, byPixels,
|
|
||||||
positiveSeekStep, byPixels);
|
|
||||||
|
|
||||||
ModifyState(false);
|
ModifyState(false);
|
||||||
}
|
}
|
||||||
|
39
src/Menus.h
39
src/Menus.h
@ -544,17 +544,40 @@ void NextWindow(const CommandContext &context );
|
|||||||
void OnResample(const CommandContext &context );
|
void OnResample(const CommandContext &context );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnCursorLeft(bool shift, bool ctrl, bool keyup = false);
|
enum SelectionOperation {
|
||||||
void OnCursorRight(bool shift, bool ctrl, bool keyup = false);
|
SELECTION_EXTEND,
|
||||||
void OnCursorMove(bool forward, bool jump, bool longjump);
|
SELECTION_CONTRACT,
|
||||||
void OnBoundaryMove(bool left, bool boundaryContract);
|
CURSOR_MOVE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CursorDirection {
|
||||||
|
DIRECTION_LEFT = -1,
|
||||||
|
DIRECTION_RIGHT = +1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TimeUnit {
|
||||||
|
TIME_UNIT_SECONDS,
|
||||||
|
TIME_UNIT_PIXELS
|
||||||
|
};
|
||||||
|
|
||||||
|
bool OnlyHandleKeyUp( const CommandContext &context );
|
||||||
|
void OnCursorMove(double seekStep);
|
||||||
|
void OnBoundaryMove(int step);
|
||||||
|
|
||||||
// Handle small cursor and play head movements
|
// Handle small cursor and play head movements
|
||||||
void SeekLeftOrRight
|
void SeekLeftOrRight
|
||||||
(bool left, bool shift, bool ctrl, bool keyup,
|
(double direction, SelectionOperation operation);
|
||||||
int snapToTime, bool mayAccelerateQuiet, bool mayAccelerateAudio,
|
|
||||||
double quietSeekStepPositive, bool quietStepIsPixels,
|
void SeekWhenAudioActive(double seekStep);
|
||||||
double audioSeekStepPositive, bool audioStepIsPixels);
|
void SeekWhenAudioInactive
|
||||||
|
(double seekStep, TimeUnit timeUnit,
|
||||||
|
SelectionOperation operation);
|
||||||
|
void MoveWhenAudioInactive
|
||||||
|
(double seekStep, TimeUnit timeUnit);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
double OffsetTime(double t, double offset, TimeUnit timeUnit, int snapToTime);
|
||||||
|
|
||||||
// Helper for moving by keyboard with snap-to-grid enabled
|
// Helper for moving by keyboard with snap-to-grid enabled
|
||||||
double GridMove(double t, int minPix);
|
double GridMove(double t, int minPix);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user