diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 5bf790d04..4cb99f463 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -643,6 +643,14 @@ void NoteTrack::InsertSilence(double t, double len) // AddToDuration( len ); } +void NoteTrack::SetVelocity(float velocity) +{ + if (mVelocity != velocity) { + mVelocity = velocity; + Notify(); + } +} + // Call this function to manipulate the underlying sequence data. This is // NOT the function that handles horizontal dragging. bool NoteTrack::Shift(double t) // t is always seconds diff --git a/src/NoteTrack.h b/src/NoteTrack.h index 0066ce12d..6179c03cd 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -114,7 +114,7 @@ class AUDACITY_DLL_API NoteTrack final #ifdef EXPERIMENTAL_MIDI_OUT float GetVelocity() const { return mVelocity; } - void SetVelocity(float velocity) { mVelocity = velocity; } + void SetVelocity(float velocity); #endif QuantizedTimeAndBeat NearestBeatTime( double time ) const; diff --git a/src/Track.cpp b/src/Track.cpp index c090e0319..583535968 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -91,9 +91,22 @@ void Track::Init(const Track &orig) mChannel = orig.mChannel; } +void Track::SetName( const wxString &n ) +{ + if ( mName != n ) { + mName = n; + Notify(); + } +} + void Track::SetSelected(bool s) { - mSelected = s; + if (mSelected != s) { + mSelected = s; + auto pList = mList.lock(); + if (pList) + pList->SelectionEvent( Pointer( this ) ); + } } void Track::Merge(const Track &orig) @@ -328,6 +341,13 @@ bool Track::IsSyncLockSelected() const return false; } +void Track::Notify( int code ) +{ + auto pList = mList.lock(); + if (pList) + pList->DataEvent( Pointer(this), code ); +} + void Track::SyncLockAdjust(double oldT1, double newT1) { if (newT1 > oldT1) { @@ -367,6 +387,22 @@ void PlayableTrack::Merge( const Track &orig ) AudioTrack::Merge( *pOrig ); } +void PlayableTrack::SetMute( bool m ) +{ + if ( mMute != m ) { + mMute = m; + Notify(); + } +} + +void PlayableTrack::SetSolo( bool s ) +{ + if ( mSolo != s ) { + mSolo = s; + Notify(); + } +} + // Serialize, not with tags of its own, but as attributes within a tag. void PlayableTrack::WriteXMLAttributes(XMLWriter &xmlFile) const { @@ -513,9 +549,12 @@ std::pair TrackList::FindSyncLockGroup(Track *pMember) const // is managing. Any other classes that may be interested in get these updates // should use TrackList::Connect() or TrackList::Bind(). // -wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, wxCommandEvent); -wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, wxCommandEvent); -wxDEFINE_EVENT(EVT_TRACKLIST_DELETION, wxCommandEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_SELECTION_CHANGE, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_ADDITION, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_DELETION, TrackListEvent); // same value as in the default constructed TrackId: long TrackList::sCounter = -1; @@ -592,26 +631,42 @@ void TrackList::RecalcPositions(TrackNodePointer node) UpdatePendingTracks(); } +void TrackList::SelectionEvent( const std::shared_ptr &pTrack ) +{ + // wxWidgets will own the event object + QueueEvent( + safenew TrackListEvent{ EVT_TRACKLIST_SELECTION_CHANGE, pTrack } ); +} + +void TrackList::DataEvent( const std::shared_ptr &pTrack, int code ) +{ + // wxWidgets will own the event object + QueueEvent( + safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } ); +} + void TrackList::PermutationEvent() { - auto e = std::make_unique(EVT_TRACKLIST_PERMUTED); // wxWidgets will own the event object - QueueEvent(e.release()); + QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_PERMUTED } ); } void TrackList::DeletionEvent() { - auto e = std::make_unique(EVT_TRACKLIST_DELETION); // wxWidgets will own the event object - QueueEvent(e.release()); + QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_DELETION } ); +} + +void TrackList::AdditionEvent(TrackNodePointer node) +{ + // wxWidgets will own the event object + QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_ADDITION, *node.first } ); } void TrackList::ResizingEvent(TrackNodePointer node) { - auto e = std::make_unique(EVT_TRACKLIST_RESIZING); - e->mpTrack = *node.first; // wxWidgets will own the event object - QueueEvent(e.release()); + QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_RESIZING, *node.first } ); } auto TrackList::EmptyRange() const @@ -678,7 +733,7 @@ Track *TrackList::Add(std::unique_ptr &&t) pTrack->SetOwner(mSelf, n); pTrack->SetId( TrackId{ ++sCounter } ); RecalcPositions(n); - ResizingEvent(n); + AdditionEvent(n); return back().get(); } @@ -700,7 +755,7 @@ Track *TrackList::AddToHead(std::unique_ptr &&t) pTrack->SetOwner(mSelf, n); pTrack->SetId( TrackId{ ++sCounter } ); RecalcPositions(n); - ResizingEvent(n); + AdditionEvent(n); return front().get(); } @@ -717,7 +772,7 @@ Track *TrackList::Add(std::shared_ptr &&t) t->SetOwner(mSelf, n); t->SetId( TrackId{ ++sCounter } ); RecalcPositions(n); - ResizingEvent(n); + AdditionEvent(n); return back().get(); } @@ -794,7 +849,7 @@ auto TrackList::Replace(Track * t, ListOfTracks::value_type &&with) -> RecalcPositions(node); DeletionEvent(); - ResizingEvent(node); + AdditionEvent(node); } return holder; } diff --git a/src/Track.h b/src/Track.h index 01f8c6fc9..795c411c7 100644 --- a/src/Track.h +++ b/src/Track.h @@ -205,8 +205,10 @@ class AUDACITY_DLL_API Track /* not final */ wxString mName; wxString mDefaultName; + private: bool mSelected; + protected: bool mLinked; bool mMinimized; @@ -367,7 +369,7 @@ private: virtual void Merge(const Track &orig); wxString GetName() const { return mName; } - void SetName( const wxString &n ) { mName = n; } + void SetName( const wxString &n ); wxString GetDefaultName() const { return mDefaultName; } void SetDefaultName( const wxString &n ) { mDefaultName = n; } @@ -714,6 +716,11 @@ public: // Checks if sync-lock is on and any track in its sync-lock group is selected. bool IsSyncLockSelected() const; + // Send an event to listeners when state of the track changes + // To do: define values for the argument to distinguish different parts + // of the state, perhaps with wxNewId + void Notify( int code = -1 ); + // An always-true predicate useful for defining iterators bool Any() const; @@ -763,8 +770,8 @@ public: bool GetMute () const { return mMute; } bool GetSolo () const { return mSolo; } - void SetMute (bool m) { mMute = m; } - void SetSolo (bool s) { mSolo = s; } + void SetMute (bool m); + void SetSolo (bool s); void Init( const PlayableTrack &init ); void Merge( const Track &init ) override; @@ -1086,31 +1093,50 @@ template < * Clear, and Contains, plus serialization of the list of tracks. */ -struct TrackListEvent : public wxCommandEvent +struct TrackListEvent : public wxEvent { - TrackListEvent(wxEventType commandType = wxEVT_NULL, int winid = 0) - : wxCommandEvent{ commandType, winid } {} + explicit + TrackListEvent( + wxEventType commandType, + const std::weak_ptr &pTrack = {}, int code = -1) + : wxEvent{ commandType } + , mpTrack{ pTrack } + , mCode{ code } + {} TrackListEvent( const TrackListEvent& ) = default; wxEvent *Clone() const override { return new TrackListEvent(*this); } std::weak_ptr mpTrack; + int mCode; }; +// Posted when the set of selected tracks changes. +wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, + EVT_TRACKLIST_SELECTION_CHANGE, TrackListEvent); + +// Posted when certain fields of a track change. +wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, + EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); + // Posted when tracks are reordered but otherwise unchanged. wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, - EVT_TRACKLIST_PERMUTED, wxCommandEvent); + EVT_TRACKLIST_PERMUTED, TrackListEvent); -// Posted when some track was added or changed its height. -// Cast to TrackListEvent and examine mpTrack to retrieve it. +// Posted when some track changed its height. wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, - EVT_TRACKLIST_RESIZING, wxCommandEvent); + EVT_TRACKLIST_RESIZING, TrackListEvent); + +// Posted when a track has been added to a tracklist. +// Also posted when one track replaces another +wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, + EVT_TRACKLIST_ADDITION, TrackListEvent); // Posted when a track has been deleted from a tracklist. // Also posted when one track replaces another wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, - EVT_TRACKLIST_DELETION, wxCommandEvent); + EVT_TRACKLIST_DELETION, TrackListEvent); class TrackList final : public wxEvtHandler, public ListOfTracks { @@ -1495,8 +1521,11 @@ private: } void RecalcPositions(TrackNodePointer node); + void SelectionEvent( const std::shared_ptr &pTrack ); void PermutationEvent(); + void DataEvent( const std::shared_ptr &pTrack, int code ); void DeletionEvent(); + void AdditionEvent(TrackNodePointer node); void ResizingEvent(TrackNodePointer node); void SwapNodes(TrackNodePointer s1, TrackNodePointer s2); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 2ea6a23ce..7ee00e702 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -332,6 +332,9 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mTracks->Bind(EVT_TRACKLIST_RESIZING, &TrackPanel::OnTrackListResizing, this); + mTracks->Bind(EVT_TRACKLIST_ADDITION, + &TrackPanel::OnTrackListResizing, + this); mTracks->Bind(EVT_TRACKLIST_DELETION, &TrackPanel::OnTrackListDeletion, this); @@ -781,7 +784,7 @@ void TrackPanel::UpdateViewIfNoTracks() } } -void TrackPanel::OnPlayback(wxCommandEvent &e) +void TrackPanel::OnPlayback(wxEvent &e) { e.Skip(); // Starting or stopping of play or record affects some cursors. @@ -792,9 +795,9 @@ void TrackPanel::OnPlayback(wxCommandEvent &e) // The tracks positions within the list have changed, so update the vertical // ruler size for the track that triggered the event. -void TrackPanel::OnTrackListResizing(wxCommandEvent & e) +void TrackPanel::OnTrackListResizing(TrackListEvent & e) { - auto t = static_cast(e).mpTrack.lock(); + auto t = e.mpTrack.lock(); // A deleted track can trigger the event. In which case do nothing here. if( t ) UpdateVRuler(t.get()); @@ -802,7 +805,7 @@ void TrackPanel::OnTrackListResizing(wxCommandEvent & e) } // Tracks have been removed from the list. -void TrackPanel::OnTrackListDeletion(wxCommandEvent & e) +void TrackPanel::OnTrackListDeletion(wxEvent & e) { // copy shared_ptr for safety, as in HandleClick auto handle = Target(); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 91e99acc4..17c8b08ec 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -33,6 +33,7 @@ class LabelTrack; class SpectrumAnalyst; class Track; class TrackList; +class TrackListEvent; class TrackPanel; class TrackArtist; class Ruler; @@ -41,7 +42,6 @@ class AdornedRulerPanel; class LWSlider; class ControlToolBar; //Needed because state of controls can affect what gets drawn. class ToolsToolBar; //Needed because state of controls can affect what gets drawn. -class MixerBoard; class TrackPanelAx; class TrackPanelCellIterator; @@ -257,9 +257,9 @@ class AUDACITY_DLL_API TrackPanel final : public CellularPanel { void OnMouseEvent(wxMouseEvent & event); void OnKeyDown(wxKeyEvent & event); - void OnPlayback(wxCommandEvent &); - void OnTrackListResizing(wxCommandEvent & event); - void OnTrackListDeletion(wxCommandEvent & event); + void OnPlayback(wxEvent &); + void OnTrackListResizing(TrackListEvent & event); + void OnTrackListDeletion(wxEvent & event); void UpdateViewIfNoTracks(); // Call this to update mViewInfo, etc, after track(s) removal, before Refresh(). double GetMostRecentXPos(); diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 815536a21..131fa1f66 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -422,7 +422,10 @@ float WaveTrack::GetGain() const void WaveTrack::SetGain(float newGain) { - mGain = newGain; + if (mGain != newGain) { + mGain = newGain; + Notify(); + } } float WaveTrack::GetPan() const @@ -433,11 +436,14 @@ float WaveTrack::GetPan() const void WaveTrack::SetPan(float newPan) { if (newPan > 1.0) - mPan = 1.0; + newPan = 1.0; else if (newPan < -1.0) - mPan = -1.0; - else + newPan = -1.0; + + if ( mPan != newPan ) { mPan = newPan; + Notify(); + } } float WaveTrack::GetChannelGain(int channel) const