mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-08 15:52:53 +02:00
191 lines
5.5 KiB
C++
191 lines
5.5 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
SelectionState.h
|
|
|
|
**********************************************************************/
|
|
|
|
#include "Audacity.h"
|
|
#include "SelectionState.h"
|
|
#include "MixerBoard.h"
|
|
#include "ViewInfo.h"
|
|
#include "Track.h"
|
|
|
|
// Set selection length to the length of a track -- but if sync-lock is turned
|
|
// on, use the largest possible selection in the sync-lock group.
|
|
// If it's a stereo track, do the same for the stereo channels.
|
|
void SelectionState::SelectTrackLength
|
|
( TrackList &tracks, ViewInfo &viewInfo, Track &track, bool syncLocked )
|
|
{
|
|
SyncLockedTracksIterator it( &tracks );
|
|
Track *t1 = it.StartWith( &track );
|
|
double minOffset = track.GetOffset();
|
|
double maxEnd = track.GetEndTime();
|
|
|
|
// If we have a sync-lock group and sync-lock linking is on,
|
|
// check the sync-lock group tracks.
|
|
if ( syncLocked && t1 != NULL )
|
|
{
|
|
for ( ; t1; t1 = it.Next())
|
|
{
|
|
if (t1->GetOffset() < minOffset)
|
|
minOffset = t1->GetOffset();
|
|
if (t1->GetEndTime() > maxEnd)
|
|
maxEnd = t1->GetEndTime();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, check for a stereo pair
|
|
t1 = track.GetLink();
|
|
if (t1)
|
|
{
|
|
if (t1->GetOffset() < minOffset)
|
|
minOffset = t1->GetOffset();
|
|
if (t1->GetEndTime() > maxEnd)
|
|
maxEnd = t1->GetEndTime();
|
|
}
|
|
}
|
|
|
|
// PRL: double click or click on track control.
|
|
// should this select all frequencies too? I think not.
|
|
viewInfo.selectedRegion.setTimes(minOffset, maxEnd);
|
|
}
|
|
|
|
void SelectionState::SelectTrack
|
|
( TrackList &tracks, Track &track, bool selected, bool updateLastPicked,
|
|
MixerBoard *pMixerBoard )
|
|
{
|
|
bool wasCorrect = (selected == track.GetSelected());
|
|
|
|
tracks.Select( &track, selected );
|
|
if (updateLastPicked)
|
|
mLastPickedTrack = &track;
|
|
|
|
//The older code below avoids an anchor on an unselected track.
|
|
|
|
/*
|
|
if (selected) {
|
|
// This handles the case of linked tracks, selecting all channels
|
|
mTracks->Select(pTrack, true);
|
|
if (updateLastPicked)
|
|
mLastPickedTrack = pTrack;
|
|
}
|
|
else {
|
|
mTracks->Select(pTrack, false);
|
|
if (updateLastPicked && pTrack == mLastPickedTrack)
|
|
mLastPickedTrack = nullptr;
|
|
}
|
|
*/
|
|
|
|
// Update mixer board, but only as needed so it does not flicker.
|
|
if (!wasCorrect) {
|
|
auto pt = dynamic_cast< PlayableTrack* >( &track );
|
|
if (pMixerBoard && pt)
|
|
pMixerBoard->RefreshTrackCluster( pt );
|
|
}
|
|
}
|
|
|
|
void SelectionState::SelectRangeOfTracks
|
|
( TrackList &tracks, Track &rsTrack, Track &reTrack, MixerBoard *pMixerBoard )
|
|
{
|
|
Track *sTrack = &rsTrack, *eTrack = &reTrack;
|
|
// Swap the track pointers if needed
|
|
if (eTrack->GetIndex() < sTrack->GetIndex())
|
|
std::swap(sTrack, eTrack);
|
|
|
|
TrackListIterator iter( &tracks );
|
|
sTrack = iter.StartWith( sTrack );
|
|
do {
|
|
SelectTrack( tracks, *sTrack, true, false, pMixerBoard );
|
|
if ( sTrack == eTrack ) {
|
|
break;
|
|
}
|
|
|
|
sTrack = iter.Next();
|
|
} while ( sTrack );
|
|
}
|
|
|
|
void SelectionState::SelectNone( TrackList &tracks, MixerBoard *pMixerBoard )
|
|
{
|
|
TrackListIterator iter( &tracks );
|
|
Track *track = iter.First();
|
|
while ( track ) {
|
|
SelectTrack( tracks, *track, false, false, pMixerBoard );
|
|
track = iter.Next();
|
|
}
|
|
}
|
|
|
|
void SelectionState::ChangeSelectionOnShiftClick
|
|
( TrackList &tracks, Track &track, MixerBoard *pMixerBoard )
|
|
{
|
|
|
|
// Optional: Track already selected? Nothing to do.
|
|
// If we enable this, Shift-Click behaves like click in this case.
|
|
//if( pTrack->GetSelected() )
|
|
// return;
|
|
|
|
// Find first and last selected track.
|
|
Track* pFirst = nullptr;
|
|
Track* pLast = nullptr;
|
|
// We will either extend from the first or from the last.
|
|
Track* pExtendFrom= nullptr;
|
|
|
|
if( mLastPickedTrack )
|
|
pExtendFrom = mLastPickedTrack;
|
|
else {
|
|
TrackListIterator iter( &tracks );
|
|
for (Track *t = iter.First(); t; t = iter.Next()) {
|
|
const bool isSelected = t->GetSelected();
|
|
// Record first and last selected.
|
|
if( isSelected ) {
|
|
if( !pFirst )
|
|
pFirst = t;
|
|
pLast = t;
|
|
}
|
|
// If our track is at or after the first, extend from the first.
|
|
if( t == &track )
|
|
pExtendFrom = pFirst;
|
|
}
|
|
// Our track was earlier than the first. Extend from the last.
|
|
if( !pExtendFrom )
|
|
pExtendFrom = pLast;
|
|
}
|
|
|
|
SelectNone( tracks, pMixerBoard );
|
|
if( pExtendFrom )
|
|
SelectRangeOfTracks( tracks, track, *pExtendFrom, pMixerBoard );
|
|
else
|
|
SelectTrack( tracks, track, true, true, pMixerBoard );
|
|
mLastPickedTrack = pExtendFrom;
|
|
}
|
|
|
|
void SelectionState::HandleListSelection
|
|
( TrackList &tracks, ViewInfo &viewInfo,
|
|
Track &track, bool shift, bool ctrl, bool syncLocked, MixerBoard *pMixerBoard )
|
|
{
|
|
// AS: If the shift button is being held down, invert
|
|
// the selection on this track.
|
|
if (ctrl)
|
|
SelectTrack( tracks, track, !track.GetSelected(), true, pMixerBoard );
|
|
else {
|
|
if (shift && mLastPickedTrack)
|
|
ChangeSelectionOnShiftClick( tracks, track, pMixerBoard );
|
|
else {
|
|
SelectNone( tracks, pMixerBoard );
|
|
SelectTrack( tracks, track, true, true, pMixerBoard );
|
|
SelectTrackLength( tracks, viewInfo, track, syncLocked );
|
|
}
|
|
|
|
if (pMixerBoard)
|
|
pMixerBoard->RefreshTrackClusters();
|
|
}
|
|
}
|
|
|
|
void SelectionState::TrackListUpdated( const TrackList &tracks )
|
|
{
|
|
if (mLastPickedTrack && !tracks.Contains(mLastPickedTrack))
|
|
mLastPickedTrack = nullptr;
|
|
}
|