1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-03 17:39:25 +02:00

Define class SelectionState; move some TrackPanel functions into it

This commit is contained in:
Paul Licameli 2017-06-11 07:20:01 -04:00 committed by Paul Licameli
parent 986f158efa
commit a594207265
9 changed files with 323 additions and 209 deletions

View File

@ -1208,6 +1208,7 @@
5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; };
5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842F1DF1E4F400CA76EA /* UserException.cpp */; };
5E0A0E311D23019A00CD2567 /* MenusMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */; };
5E2A19941EED688500217B58 /* SelectionState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2A19921EED688500217B58 /* SelectionState.cpp */; };
5E74D2E31CC4429700D88B0B /* EditCursorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DD1CC4429700D88B0B /* EditCursorOverlay.cpp */; };
5E74D2E41CC4429700D88B0B /* PlayIndicatorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2DF1CC4429700D88B0B /* PlayIndicatorOverlay.cpp */; };
5E74D2E51CC4429700D88B0B /* Scrubbing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E74D2E11CC4429700D88B0B /* Scrubbing.cpp */; };
@ -2988,6 +2989,8 @@
5E07842F1DF1E4F400CA76EA /* UserException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserException.cpp; sourceTree = "<group>"; };
5E0784301DF1E4F400CA76EA /* UserException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserException.h; sourceTree = "<group>"; };
5E0A0E301D23019A00CD2567 /* MenusMac.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MenusMac.cpp; sourceTree = "<group>"; };
5E2A19921EED688500217B58 /* SelectionState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionState.cpp; sourceTree = "<group>"; };
5E2A19931EED688500217B58 /* SelectionState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionState.h; sourceTree = "<group>"; };
5E4685F81CCA9D84008741F2 /* CommandFunctors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommandFunctors.h; sourceTree = "<group>"; };
5E61EE0C1CBAA6BB0009FCF1 /* MemoryX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryX.h; sourceTree = "<group>"; };
5E74D2D91CC4427B00D88B0B /* TrackPanelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelCell.h; sourceTree = "<group>"; };
@ -3909,6 +3912,7 @@
1790B0D609883BFD008A330A /* SampleFormat.cpp */,
285DE1F80BF03C7800A20DF0 /* Screenshot.cpp */,
28D8425B1AD8D69D00551353 /* SelectedRegion.cpp */,
5E2A19921EED688500217B58 /* SelectionState.cpp */,
1790B0DA09883BFD008A330A /* Sequence.cpp */,
1790B0DC09883BFD008A330A /* Shuttle.cpp */,
283A11A60A2C0E15004372C4 /* ShuttleGui.cpp */,
@ -4005,6 +4009,7 @@
1790B0D709883BFD008A330A /* SampleFormat.h */,
285DE1F90BF03C7800A20DF0 /* Screenshot.h */,
2813897919E6163C004111ED /* SelectedRegion.h */,
5E2A19931EED688500217B58 /* SelectionState.h */,
1790B0DB09883BFD008A330A /* Sequence.h */,
1790B0DD09883BFD008A330A /* Shuttle.h */,
283A11A70A2C0E15004372C4 /* ShuttleGui.h */,
@ -7472,6 +7477,7 @@
1790B1A709883BFD008A330A /* Warning.cpp in Sources */,
1790B1A909883BFD008A330A /* XMLFileReader.cpp in Sources */,
1790B1AA09883BFD008A330A /* XMLTagHandler.cpp in Sources */,
5E2A19941EED688500217B58 /* SelectionState.cpp in Sources */,
17190D24098A3F0B004583C6 /* AColor.cpp in Sources */,
17190D25098A3F15004583C6 /* AboutDialog.cpp in Sources */,
174D9031098C78AF00D5909F /* CommandManager.cpp in Sources */,

View File

@ -206,6 +206,8 @@ audacity_SOURCES = \
Screenshot.h \
SelectedRegion.cpp \
SelectedRegion.h \
SelectionState.cpp \
SelectionState.h \
Shuttle.cpp \
Shuttle.h \
ShuttleGui.cpp \

View File

@ -315,8 +315,9 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h Resample.cpp \
Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \
Screenshot.cpp Screenshot.h SelectedRegion.cpp \
SelectedRegion.h Shuttle.cpp Shuttle.h ShuttleGui.cpp \
ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SelectedRegion.h SelectionState.cpp SelectionState.h \
Shuttle.cpp Shuttle.h ShuttleGui.cpp ShuttleGui.h \
ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
Spectrum.h SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
SseMathFuncs.h Tags.cpp Tags.h Theme.cpp Theme.h \
@ -575,7 +576,8 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \
audacity-RealFFTf.$(OBJEXT) audacity-RealFFTf48x.$(OBJEXT) \
audacity-Resample.$(OBJEXT) audacity-RingBuffer.$(OBJEXT) \
audacity-Screenshot.$(OBJEXT) \
audacity-SelectedRegion.$(OBJEXT) audacity-Shuttle.$(OBJEXT) \
audacity-SelectedRegion.$(OBJEXT) \
audacity-SelectionState.$(OBJEXT) audacity-Shuttle.$(OBJEXT) \
audacity-ShuttleGui.$(OBJEXT) audacity-ShuttlePrefs.$(OBJEXT) \
audacity-Snap.$(OBJEXT) \
audacity-SoundActivatedRecord.$(OBJEXT) \
@ -1018,6 +1020,8 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PORTAUDIO_CFLAGS = @PORTAUDIO_CFLAGS@
PORTAUDIO_LIBS = @PORTAUDIO_LIBS@
PORTMIXER_LIBS = @PORTMIXER_LIBS@
@ -1095,7 +1099,6 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@ -1219,8 +1222,9 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h Resample.cpp \
Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \
Screenshot.cpp Screenshot.h SelectedRegion.cpp \
SelectedRegion.h Shuttle.cpp Shuttle.h ShuttleGui.cpp \
ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SelectedRegion.h SelectionState.cpp SelectionState.h \
Shuttle.cpp Shuttle.h ShuttleGui.cpp ShuttleGui.h \
ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
Spectrum.h SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
SseMathFuncs.h Tags.cpp Tags.h Theme.cpp Theme.h \
@ -2126,6 +2130,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-SampleFormat.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Screenshot.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-SelectedRegion.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-SelectionState.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Sequence.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Shuttle.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-ShuttleGui.Po@am__quote@
@ -3455,6 +3460,20 @@ audacity-SelectedRegion.obj: SelectedRegion.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-SelectedRegion.obj `if test -f 'SelectedRegion.cpp'; then $(CYGPATH_W) 'SelectedRegion.cpp'; else $(CYGPATH_W) '$(srcdir)/SelectedRegion.cpp'; fi`
audacity-SelectionState.o: SelectionState.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-SelectionState.o -MD -MP -MF $(DEPDIR)/audacity-SelectionState.Tpo -c -o audacity-SelectionState.o `test -f 'SelectionState.cpp' || echo '$(srcdir)/'`SelectionState.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-SelectionState.Tpo $(DEPDIR)/audacity-SelectionState.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SelectionState.cpp' object='audacity-SelectionState.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-SelectionState.o `test -f 'SelectionState.cpp' || echo '$(srcdir)/'`SelectionState.cpp
audacity-SelectionState.obj: SelectionState.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-SelectionState.obj -MD -MP -MF $(DEPDIR)/audacity-SelectionState.Tpo -c -o audacity-SelectionState.obj `if test -f 'SelectionState.cpp'; then $(CYGPATH_W) 'SelectionState.cpp'; else $(CYGPATH_W) '$(srcdir)/SelectionState.cpp'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-SelectionState.Tpo $(DEPDIR)/audacity-SelectionState.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='SelectionState.cpp' object='audacity-SelectionState.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-SelectionState.obj `if test -f 'SelectionState.cpp'; then $(CYGPATH_W) 'SelectionState.cpp'; else $(CYGPATH_W) '$(srcdir)/SelectionState.cpp'; fi`
audacity-Shuttle.o: Shuttle.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-Shuttle.o -MD -MP -MF $(DEPDIR)/audacity-Shuttle.Tpo -c -o audacity-Shuttle.o `test -f 'Shuttle.cpp' || echo '$(srcdir)/'`Shuttle.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-Shuttle.Tpo $(DEPDIR)/audacity-Shuttle.Po

190
src/SelectionState.cpp Normal file
View File

@ -0,0 +1,190 @@
/**********************************************************************
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;
}

43
src/SelectionState.h Normal file
View File

@ -0,0 +1,43 @@
/**********************************************************************
Audacity: A Digital Audio Editor
SelectionState.h
**********************************************************************/
#ifndef __AUDACITY_SELECTION_STATE__
#define __AUDACITY_SELECTION_STATE__
class Track;
class TrackList;
class MixerBoard;
class ViewInfo;
// State relating to the set of selected tracks
class SelectionState
{
public:
static void SelectTrackLength
( TrackList &tracks, ViewInfo &viewInfo, Track &track, bool syncLocked );
void SelectTrack
( TrackList &tracks, Track &track,
bool selected, bool updateLastPicked, MixerBoard *pMixerBoard );
// Inclusive range of tracks, the limits specified in either order:
void SelectRangeOfTracks
( TrackList &tracks, Track &sTrack, Track &eTrack,
MixerBoard *pMixerBoard );
void SelectNone( TrackList &tracks, MixerBoard *pMixerBoard );
void ChangeSelectionOnShiftClick
( TrackList &tracks, Track &track, MixerBoard *pMixerBoard );
void HandleListSelection
( TrackList &tracks, ViewInfo &viewInfo, Track &track,
bool shift, bool ctrl, bool syncLocked, MixerBoard *pMixerBoard );
void TrackListUpdated( const TrackList &tracks );
Track *mLastPickedTrack {};
};
#endif

View File

@ -798,16 +798,6 @@ void TrackPanel::SetCapturedTrack( Track * t, enum MouseCaptureEnum MouseCapture
mMouseCapture = MouseCapture;
}
void TrackPanel::SelectNone()
{
TrackListIterator iter(GetTracks());
Track *t = iter.First();
while (t) {
SelectTrack(t, false, false);
t = iter.Next();
}
}
/// Select all tracks marked by the label track lt
void TrackPanel::SelectTracksByLabel( LabelTrack *lt )
{
@ -825,52 +815,11 @@ void TrackPanel::SelectTracksByLabel( LabelTrack *lt )
t = iter.First();
while( t )
{
SelectTrack(t, true);
GetSelectionState().SelectTrack( *mTracks, *t, true, true, GetMixerBoard() );
t = iter.Next();
}
}
// 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 TrackPanel::SelectTrackLength(Track *t)
{
AudacityProject *p = GetActiveProject();
SyncLockedTracksIterator it(GetTracks());
Track *t1 = it.StartWith(t);
double minOffset = t->GetOffset();
double maxEnd = t->GetEndTime();
// If we have a sync-lock group and sync-lock linking is on,
// check the sync-lock group tracks.
if (p->IsSyncLocked() && 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 = t->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.
mViewInfo->selectedRegion.setTimes(minOffset, maxEnd);
}
void TrackPanel::GetTracksUsableArea(int *width, int *height) const
{
GetSize(width, height);
@ -1210,7 +1159,7 @@ bool TrackPanel::HandleEscapeKey(bool down)
wxASSERT(it != end);
t->SetSelected(*it++);
}
mLastPickedTrack = mInitialLastPickedTrack;
GetSelectionState().mLastPickedTrack = mInitialLastPickedTrack;
mViewInfo->selectedRegion = mInitialSelection;
// Refresh mixer board for change of set of selected tracks
@ -1899,12 +1848,14 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
}
// Deselect all other tracks and select this one.
SelectNone();
GetSelectionState().SelectNone( *mTracks, GetMixerBoard() );
SelectTrack(mCapturedTrack, true);
GetSelectionState().SelectTrack
( *mTracks, *mCapturedTrack, true, true, GetMixerBoard() );
// Default behavior: select whole track
SelectTrackLength(mCapturedTrack);
SelectionState::SelectTrackLength
( *mTracks, *mViewInfo, *mCapturedTrack, GetProject()->IsSyncLocked() );
// Special case: if we're over a clip in a WaveTrack,
// select just that clip
@ -1936,39 +1887,6 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
SelectionHandleDrag(event, t);
}
void TrackPanel::SelectTrack(Track *pTrack, bool selected, bool updateLastPicked)
{
bool wasCorrect = (selected == pTrack->GetSelected());
mTracks->Select(pTrack, selected);
if (updateLastPicked)
mLastPickedTrack = pTrack;
//Thw 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) {
MixerBoard* pMixerBoard = this->GetMixerBoard();
auto pt = dynamic_cast< PlayableTrack* >( pTrack );
if (pMixerBoard && pt)
pMixerBoard->RefreshTrackCluster( pt );
}
}
// Counts tracks, counting stereo tracks as one track.
size_t TrackPanel::GetTrackCount(){
size_t count = 0;
@ -2001,71 +1919,6 @@ size_t TrackPanel::GetSelectedTrackCount(){
return count;
}
void TrackPanel::SelectRangeOfTracks(Track *sTrack, Track *eTrack)
{
if (eTrack) {
// Swap the track pointers if needed
if (eTrack->GetIndex() < sTrack->GetIndex())
std::swap(sTrack, eTrack);
TrackListIterator iter(GetTracks());
sTrack = iter.StartWith(sTrack);
do {
SelectTrack(sTrack, true, false);
if (sTrack == eTrack) {
break;
}
sTrack = iter.Next();
} while (sTrack);
}
}
void TrackPanel::ChangeSelectionOnShiftClick(Track * pTrack){
// 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(GetTracks());
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 == pTrack ){
pExtendFrom = pFirst;
}
}
// Our track was earlier than the first. Extend from the last.
if( !pExtendFrom )
pExtendFrom = pLast;
}
SelectNone();
if( pExtendFrom )
SelectRangeOfTracks(pTrack, pExtendFrom);
else
SelectTrack( pTrack, true );
mLastPickedTrack = pExtendFrom;
}
/// This method gets called when we're handling selection
/// and the mouse was just clicked.
void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
@ -2078,7 +1931,7 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
mMouseCapture=IsSelecting;
mInitialSelection = mViewInfo->selectedRegion;
mInitialLastPickedTrack = mLastPickedTrack;
mInitialLastPickedTrack = GetSelectionState().mLastPickedTrack;
// Save initial state of track selections
mInitialTrackSelection.clear();
@ -2110,7 +1963,8 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
)) {
if( bShiftDown )
ChangeSelectionOnShiftClick( pTrack );
GetSelectionState().ChangeSelectionOnShiftClick
( *mTracks, *pTrack, GetMixerBoard() );
if( bCtrlDown ){
//Commented out bIsSelected toggles, as in Track Control Panel.
//bool bIsSelected = pTrack->GetSelected();
@ -2118,8 +1972,8 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
bool bIsSelected = false;
// Don't toggle away the last selected track.
if( !bIsSelected || GetSelectedTrackCount() > 1 )
SelectTrack( pTrack, !bIsSelected, true );
mLastPickedTrack = pTrack;
GetSelectionState().SelectTrack
( *mTracks, *pTrack, !bIsSelected, true, GetMixerBoard() );
}
double value;
@ -2333,12 +2187,13 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
#endif
if (startNewSelection) {
// If we didn't move a selection boundary, start a NEW selection
SelectNone();
GetSelectionState().SelectNone( *mTracks, GetMixerBoard() );
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
StartFreqSelection (event.m_y, rect.y, rect.height, pTrack);
#endif
StartSelection(event.m_x, rect.x);
SelectTrack(pTrack, true);
GetSelectionState().SelectTrack
( *mTracks, *pTrack, true, true, GetMixerBoard() );
SetFocusedTrack(pTrack);
//On-Demand: check to see if there is an OD thing associated with this track.
if (pTrack->GetKind() == Track::Wave) {
@ -2941,8 +2796,9 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
// Handle which tracks are selected
Track *sTrack = pTrack;
Track *eTrack = FindCell(x, y).pTrack;
if( !event.ControlDown() )
SelectRangeOfTracks(sTrack, eTrack);
if( !event.ControlDown() && sTrack && eTrack )
GetSelectionState().SelectRangeOfTracks
( *mTracks, *sTrack, *eTrack, GetMixerBoard() );
#ifdef USE_MIDI
if (mStretchState.mStretching) {
@ -5141,8 +4997,7 @@ void TrackPanel::OnTrackListUpdated(wxCommandEvent & e)
ReleaseMouse();
}
if (mLastPickedTrack && !mTracks->Contains(mLastPickedTrack))
mLastPickedTrack = nullptr;
GetSelectionState().TrackListUpdated( *mTracks );
if (e.GetClientData()) {
OnTrackListResized(e);
@ -5404,28 +5259,13 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event)
void TrackPanel::HandleListSelection(Track *t, bool shift, bool ctrl,
bool modifyState)
{
// AS: If the shift button is being held down, invert
// the selection on this track.
if (ctrl) {
SelectTrack(t, !t->GetSelected(), true);
Refresh(false);
}
else {
if (shift && mLastPickedTrack)
ChangeSelectionOnShiftClick( t );
else{
SelectNone();
SelectTrack(t, true);
SelectTrackLength(t);
}
GetSelectionState().HandleListSelection
( *mTracks, *mViewInfo, *t, shift, ctrl, GetProject()->IsSyncLocked(),
GetMixerBoard() );
if (! ctrl )
SetFocusedTrack(t);
this->Refresh(false);
MixerBoard* pMixerBoard = this->GetMixerBoard();
if (pMixerBoard)
pMixerBoard->RefreshTrackClusters();
}
Refresh(false);
if (modifyState)
MakeParentModifyState(true);
}
@ -6690,7 +6530,8 @@ bool TrackPanel::HandleLabelTrackClick(LabelTrack * lTrack, const wxRect &rect,
if (lTrack->IsSelected()) {
SelectTracksByLabel(lTrack);
// Do this after, for the effect on mLastPickedTrack:
SelectTrack(lTrack, true);
GetSelectionState().SelectTrack
( *mTracks, *lTrack, true, true, GetMixerBoard() );
DisplaySelection();
// Not starting a drag
@ -6822,7 +6663,7 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
// AS: If the user clicked outside all tracks, make nothing
// selected.
if ((event.ButtonDown() || event.ButtonDClick()) && !pTrack) {
SelectNone();
GetSelectionState().SelectNone( *mTracks, GetMixerBoard() );
Refresh(false);
return;
}
@ -7686,7 +7527,8 @@ void TrackPanel::OnPrevTrack( bool shift )
pSelected = p->GetSelected();
if( tSelected && pSelected )
{
SelectTrack(t, false, false);
GetSelectionState().SelectTrack
( *mTracks, *t, false, false, GetMixerBoard() );
SetFocusedTrack( p ); // move focus to next track down
EnsureVisible( p );
MakeParentModifyState(false);
@ -7694,7 +7536,8 @@ void TrackPanel::OnPrevTrack( bool shift )
}
if( tSelected && !pSelected )
{
SelectTrack(p, true, false);
GetSelectionState().SelectTrack
( *mTracks, *p, true, false, GetMixerBoard() );
SetFocusedTrack( p ); // move focus to next track down
EnsureVisible( p );
MakeParentModifyState(false);
@ -7702,7 +7545,8 @@ void TrackPanel::OnPrevTrack( bool shift )
}
if( !tSelected && pSelected )
{
SelectTrack(p, false, false);
GetSelectionState().SelectTrack
( *mTracks, *p, false, false, GetMixerBoard() );
SetFocusedTrack( p ); // move focus to next track down
EnsureVisible( p );
MakeParentModifyState(false);
@ -7710,7 +7554,8 @@ void TrackPanel::OnPrevTrack( bool shift )
}
if( !tSelected && !pSelected )
{
SelectTrack(t, true, false);
GetSelectionState().SelectTrack
( *mTracks, *t, true, false, GetMixerBoard() );
SetFocusedTrack( p ); // move focus to next track down
EnsureVisible( p );
MakeParentModifyState(false);
@ -7792,7 +7637,8 @@ void TrackPanel::OnNextTrack( bool shift )
nSelected = n->GetSelected();
if( tSelected && nSelected )
{
SelectTrack(t, false, false);
GetSelectionState().SelectTrack
( *mTracks, *t, false, false, GetMixerBoard() );
SetFocusedTrack( n ); // move focus to next track down
EnsureVisible( n );
MakeParentModifyState(false);
@ -7800,7 +7646,8 @@ void TrackPanel::OnNextTrack( bool shift )
}
if( tSelected && !nSelected )
{
SelectTrack(n, true, false);
GetSelectionState().SelectTrack
( *mTracks, *n, true, false, GetMixerBoard() );
SetFocusedTrack( n ); // move focus to next track down
EnsureVisible( n );
MakeParentModifyState(false);
@ -7808,7 +7655,8 @@ void TrackPanel::OnNextTrack( bool shift )
}
if( !tSelected && nSelected )
{
SelectTrack(n, false, false);
GetSelectionState().SelectTrack
( *mTracks, *n, false, false, GetMixerBoard() );
SetFocusedTrack( n ); // move focus to next track down
EnsureVisible( n );
MakeParentModifyState(false);
@ -7816,7 +7664,8 @@ void TrackPanel::OnNextTrack( bool shift )
}
if( !tSelected && !nSelected )
{
SelectTrack(t, true, false);
GetSelectionState().SelectTrack
( *mTracks, *t, true, false, GetMixerBoard() );
SetFocusedTrack( n ); // move focus to next track down
EnsureVisible( n );
MakeParentModifyState(false);
@ -7894,7 +7743,8 @@ void TrackPanel::OnToggle()
if (!t)
return;
SelectTrack( t, !t->GetSelected() );
GetSelectionState().SelectTrack
( *mTracks, *t, !t->GetSelected(), true, GetMixerBoard() );
EnsureVisible( t );
MakeParentModifyState(false);

View File

@ -25,6 +25,8 @@
#include "Track.h"
#include "widgets/OverlayPanel.h"
#include "SelectionState.h"
class wxMenu;
class wxRect;
@ -216,8 +218,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
// Either argument may be NULL
virtual void GetTracksUsableArea(int *width, int *height) const;
virtual void SelectNone();
virtual void Refresh(bool eraseBackground = true,
const wxRect *rect = (const wxRect *) NULL);
virtual void RefreshTrack(Track *trk, bool refreshbacking = true);
@ -343,8 +343,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
#endif
// AS: Selection handling
void SelectTrack(Track *track, bool selected, bool updateLastPicked = true);
void SelectRangeOfTracks(Track *sTrack, Track *eTrack);
size_t GetTrackCount();
size_t GetSelectedTrackCount();
virtual void HandleSelect(wxMouseEvent & event);
@ -352,7 +350,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
protected:
virtual void ChangeSelectionOnShiftClick(Track * pTrack);
virtual void SelectionHandleClick(wxMouseEvent &event,
Track* pTrack, wxRect rect);
virtual void StartSelection (int mouseXCoordinate, int trackLeftEdge);
@ -381,7 +378,6 @@ protected:
#endif
virtual void SelectTracksByLabel( LabelTrack *t );
virtual void SelectTrackLength(Track *t);
// AS: Cursor handling
virtual bool SetCursorByActivity( );
@ -644,13 +640,13 @@ protected:
SelectedRegion mInitialSelection;
std::vector<bool> mInitialTrackSelection;
SelectionState mSelectionState{};
SelectionState &GetSelectionState() { return mSelectionState; }
Track *mInitialLastPickedTrack {};
bool mSelStartValid;
double mSelStart;
Track *mLastPickedTrack {};
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
enum eFreqSelMode {
FREQ_SEL_INVALID,

View File

@ -197,6 +197,7 @@
<ClCompile Include="..\..\..\src\SampleFormat.cpp" />
<ClCompile Include="..\..\..\src\Screenshot.cpp" />
<ClCompile Include="..\..\..\src\SelectedRegion.cpp" />
<ClCompile Include="..\..\..\src\SelectionState.cpp" />
<ClCompile Include="..\..\..\src\Sequence.cpp" />
<ClCompile Include="..\..\..\src\Shuttle.cpp" />
<ClCompile Include="..\..\..\src\ShuttleGui.cpp" />
@ -457,6 +458,7 @@
<ClInclude Include="..\..\..\src\RealFFTf48x.h" />
<ClInclude Include="..\..\..\src\RevisionIdent.h" />
<ClInclude Include="..\..\..\src\SelectedRegion.h" />
<ClInclude Include="..\..\..\src\SelectionState.h" />
<ClInclude Include="..\..\..\src\SseMathFuncs.h" />
<ClInclude Include="..\..\..\src\toolbars\ScrubbingToolBar.h" />
<ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBar.h" />

View File

@ -905,6 +905,9 @@
<ClCompile Include="..\..\..\src\blockfile\NotYetAvailableException.cpp">
<Filter>src\blockfile</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\SelectionState.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\src\AboutDialog.h">
@ -1834,6 +1837,9 @@
<ClInclude Include="..\..\..\src\blockfile\NotYetAvailableException.h">
<Filter>src\blockfile</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\SelectionState.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\..\audacity.ico">