From 4339c0df688ac9641358cf509856c9e43b213b6a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 08:39:20 -0400 Subject: [PATCH 1/6] Move height calculation utilities to class TrackView --- src/Printing.cpp | 3 ++- src/ProjectWindow.cpp | 3 ++- src/Track.cpp | 22 ---------------------- src/Track.h | 3 --- src/TrackPanel.cpp | 14 ++++---------- src/commands/GetInfoCommand.cpp | 2 +- src/menus/ViewMenus.cpp | 5 ++--- src/tracks/ui/TrackSelectHandle.cpp | 5 +++-- src/tracks/ui/TrackView.cpp | 23 +++++++++++++++++++++++ src/tracks/ui/TrackView.h | 9 +++++++++ 10 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/Printing.cpp b/src/Printing.cpp index b14eb7393..481b470fa 100644 --- a/src/Printing.cpp +++ b/src/Printing.cpp @@ -72,7 +72,8 @@ bool AudacityPrintout::OnPrintPage(int WXUNUSED(page)) dc->GetSize(&width, &height); int rulerScreenHeight = 40; - int screenTotalHeight = mTracks->GetHeight() + rulerScreenHeight; + int screenTotalHeight = + TrackView::GetTotalHeight( *mTracks ) + rulerScreenHeight; double scale = height / (double)screenTotalHeight; diff --git a/src/ProjectWindow.cpp b/src/ProjectWindow.cpp index e0b944730..effa0cc8f 100644 --- a/src/ProjectWindow.cpp +++ b/src/ProjectWindow.cpp @@ -29,6 +29,7 @@ Paul Licameli split from AudacityProject.cpp #include "toolbars/ControlToolBar.h" #include "toolbars/ToolManager.h" #include "tracks/ui/Scrubbing.h" +#include "tracks/ui/TrackView.h" #include "widgets/wxPanelWrapper.h" #include "widgets/WindowAccessible.h" @@ -1137,7 +1138,7 @@ void ProjectWindow::FixScrollbars() bool refresh = false; bool rescroll = false; - int totalHeight = (tracks.GetHeight() + 32); + int totalHeight = TrackView::GetTotalHeight( tracks ) + 32; int panelWidth, panelHeight; trackPanel.GetTracksUsableArea(&panelWidth, &panelHeight); diff --git a/src/Track.cpp b/src/Track.cpp index 8d34889ec..4b9fae1fd 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -842,15 +842,6 @@ Track *TrackList::GetPrev(Track * t, bool linked) const return nullptr; } -/// For mono track height of track -/// For stereo track combined height of both channels. -int TrackList::GetGroupHeight(const Track * t) const -{ - const auto GetHeight = []( const Track *track ) - { return TrackView::Get( *track ).GetHeight(); }; - return Channels(t).sum( GetHeight ); -} - bool TrackList::CanMoveUp(Track * t) const { return GetPrev(t, true) != NULL; @@ -970,19 +961,6 @@ size_t TrackList::size() const return cnt; } -int TrackList::GetHeight() const -{ - int height = 0; - - if (!empty()) { - auto track = getPrev( getEnd() ).first->get(); - auto &view = TrackView::Get( *track ); - height = view.GetY() + view.GetHeight(); - } - - return height; -} - namespace { // Abstract the common pattern of the following three member functions inline double Accumulate diff --git a/src/Track.h b/src/Track.h index 74b1bfba6..321124153 100644 --- a/src/Track.h +++ b/src/Track.h @@ -1360,8 +1360,6 @@ public: /// Make the list empty void Clear(bool sendEvent = true); - int GetGroupHeight(const Track * t) const; - bool CanMoveUp(Track * t) const; bool CanMoveDown(Track * t) const; @@ -1393,7 +1391,6 @@ public: double GetEndTime() const; double GetMinOffset() const; - int GetHeight() const; #if LEGACY_PROJECT_FILE_SUPPORT // File I/O diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 65b221f21..914cfa25b 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -832,10 +832,8 @@ void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking) trk = *GetTracks()->FindLeader(trk); auto &view = TrackView::Get( *trk ); - const auto GetHeight = []( const Track *track ) - { return TrackView::Get( *track ).GetHeight(); }; auto height = - TrackList::Channels(trk).sum( GetHeight ) + TrackList::Channels(trk).sum( TrackView::GetTrackHeight ) - kTopInset - kShadowThickness; // subtract insets and shadows from the rectangle, but not border @@ -1327,9 +1325,7 @@ void TrackPanel::EnsureVisible(Track * t) trackTop += trackHeight; auto channels = TrackList::Channels(it); - const auto GetHeight = []( const Track *track ) - { return TrackView::Get( *track ).GetHeight(); }; - trackHeight = channels.sum( GetHeight ); + trackHeight = channels.sum( TrackView::GetTrackHeight ); //We have found the track we want to ensure is visible. if (channels.contains(t)) { @@ -1363,15 +1359,13 @@ void TrackPanel::VerticalScroll( float fracPosition){ int trackHeight = 0; auto tracks = GetTracks(); - const auto GetHeight = - [&]( const Track *t ){ return tracks->GetGroupHeight(t); }; auto range = tracks->Leaders(); if (!range.empty()) { - trackHeight = GetHeight( *range.rbegin() ); + trackHeight = TrackView::GetChannelGroupHeight( *range.rbegin() ); --range.second; } - trackTop = range.sum( GetHeight ); + trackTop = range.sum( TrackView::GetChannelGroupHeight ); int delta; diff --git a/src/commands/GetInfoCommand.cpp b/src/commands/GetInfoCommand.cpp index 36eaa5513..8ea5d3f8a 100644 --- a/src/commands/GetInfoCommand.cpp +++ b/src/commands/GetInfoCommand.cpp @@ -497,7 +497,7 @@ bool GetInfoCommand::SendTracks(const CommandContext & context) context.AddBool( (trk == fTrack), "focused"); context.AddBool( trk->GetSelected(), "selected" ); //JKC: Possibly add later... - //context.AddItem( GetTrackView::Get( *trk ).GetHeight(), "height" ); + //context.AddItem( TrackView::Get( *trk ).GetHeight(), "height" ); trk->TypeSwitch( [&] (const WaveTrack* t ) { float vzmin, vzmax; t->GetDisplayBounds(&vzmin, &vzmax); diff --git a/src/menus/ViewMenus.cpp b/src/menus/ViewMenus.cpp index 4c8e8e8a6..e311aaebd 100644 --- a/src/menus/ViewMenus.cpp +++ b/src/menus/ViewMenus.cpp @@ -206,10 +206,9 @@ void DoZoomFitV(AudacityProject &project) height -= 28; // The height of minimized and non-audio tracks cannot be apportioned - const auto GetHeight = []( const Track *track ) - { return TrackView::Get( *track ).GetHeight(); }; height -= - tracks.Any().sum( GetHeight ) - range.sum( GetHeight ); + tracks.Any().sum( TrackView::GetTrackHeight ) + - range.sum( TrackView::GetTrackHeight ); // Give each resized track the average of the remaining height height = height / count; diff --git a/src/tracks/ui/TrackSelectHandle.cpp b/src/tracks/ui/TrackSelectHandle.cpp index 63738bc54..3761b3de9 100644 --- a/src/tracks/ui/TrackSelectHandle.cpp +++ b/src/tracks/ui/TrackSelectHandle.cpp @@ -11,6 +11,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../Audacity.h" #include "TrackSelectHandle.h" +#include "TrackView.h" #include "../../Menus.h" #include "../../Project.h" #include "../../ProjectAudioIO.h" @@ -219,7 +220,7 @@ void TrackSelectHandle::CalculateRearrangingThresholds(const wxMouseEvent & even if (tracks.CanMoveUp(mpTrack.get())) mMoveUpThreshold = event.m_y - - tracks.GetGroupHeight( + TrackView::GetChannelGroupHeight( * -- tracks.FindLeader( mpTrack.get() ) ); else mMoveUpThreshold = INT_MIN; @@ -227,7 +228,7 @@ void TrackSelectHandle::CalculateRearrangingThresholds(const wxMouseEvent & even if (tracks.CanMoveDown(mpTrack.get())) mMoveDownThreshold = event.m_y + - tracks.GetGroupHeight( + TrackView::GetChannelGroupHeight( * ++ tracks.FindLeader( mpTrack.get() ) ); else mMoveDownThreshold = INT_MAX; diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index 843fdee4f..bdf9ae3dd 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -18,6 +18,29 @@ TrackView::~TrackView() { } +int TrackView::GetTrackHeight( const Track *pTrack ) +{ + return pTrack ? Get( *pTrack ).GetHeight() : 0; +} + +int TrackView::GetChannelGroupHeight( const Track *pTrack ) +{ + return pTrack ? TrackList::Channels( pTrack ).sum( GetTrackHeight ) : 0; +} + +int TrackView::GetCumulativeHeight( const Track *pTrack ) +{ + if ( !pTrack ) + return 0; + auto &view = Get( *pTrack ); + return view.GetY() + view.GetHeight(); +} + +int TrackView::GetTotalHeight( const TrackList &list ) +{ + return GetCumulativeHeight( *list.Any().rbegin() ); +} + void TrackView::Copy( const TrackView &other ) { mMinimized = other.mMinimized; diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index 5fa4a564b..e1afaa32d 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -15,6 +15,7 @@ Paul Licameli split from class Track #include "CommonTrackPanelCell.h" // to inherit class Track; +class TrackList; class TrackVRulerControls; class TrackPanelResizerCell; @@ -32,6 +33,14 @@ public: : CommonTrackCell{ pTrack } {} virtual ~TrackView() = 0; + // some static conveniences, useful for summation over track iterator + // ranges + static int GetTrackHeight( const Track *pTrack ); + static int GetChannelGroupHeight( const Track *pTrack ); + // Total height of the given track and all previous ones (constant time!) + static int GetCumulativeHeight( const Track *pTrack ); + static int GetTotalHeight( const TrackList &list ); + // Copy view state, for undo/redo purposes virtual void Copy( const TrackView &other ); From 278509a5054e07e0eccabece9c3c471c3aef9bc4 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 10:13:31 -0400 Subject: [PATCH 2/6] TrackView, not TrackList, updates Y coordinates of views, using events --- src/Track.cpp | 51 ++++++++++++++++++++++------------ src/Track.h | 8 ++++-- src/tracks/ui/TrackView.cpp | 55 ++++++++++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 22 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 4b9fae1fd..4778b1d70 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -156,7 +156,6 @@ void Track::SetLinked(bool l) if (pList && !pList->mPendingUpdates.empty()) { auto orig = pList->FindById( GetId() ); if (orig && orig != this) { - // delegate, and rely on RecalcPositions to copy back orig->SetLinked(l); return; } @@ -532,23 +531,17 @@ void TrackList::RecalcPositions(TrackNodePointer node) Track *t; int i = 0; - int y = 0; auto prev = getPrev( node ); if ( !isNull( prev ) ) { t = prev.first->get(); i = t->GetIndex() + 1; - auto &view = TrackView::Get( *t ); - y = view.GetY() + view.GetHeight(); } const auto theEnd = end(); for (auto n = Find( node.first->get() ); n != theEnd; ++n) { t = *n; - auto &view = TrackView::Get( *t ); t->SetIndex(i++); - view.SetY(y); - y += view.GetHeight(); } UpdatePendingTracks(); @@ -568,16 +561,21 @@ void TrackList::DataEvent( const std::shared_ptr &pTrack, int code ) safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } ); } -void TrackList::PermutationEvent() +void TrackList::PermutationEvent(TrackNodePointer node) { // wxWidgets will own the event object - QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_PERMUTED } ); + QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_PERMUTED, *node.first } ); } -void TrackList::DeletionEvent() +void TrackList::DeletionEvent(TrackNodePointer node) { // wxWidgets will own the event object - QueueEvent( safenew TrackListEvent{ EVT_TRACKLIST_DELETION } ); + QueueEvent( safenew TrackListEvent{ + EVT_TRACKLIST_DELETION, + node.second && node.first != node.second->end() + ? *node.first + : nullptr + } ); } void TrackList::AdditionEvent(TrackNodePointer node) @@ -631,7 +629,7 @@ void TrackList::Permute(const std::vector &permutation) } auto n = getBegin(); RecalcPositions(n); - PermutationEvent(); + PermutationEvent(n); } Track *TrackList::FindById( TrackId id ) @@ -738,7 +736,7 @@ auto TrackList::Replace(Track * t, const ListOfTracks::value_type &with) -> pTrack->SetId( t->GetId() ); RecalcPositions(node); - DeletionEvent(); + DeletionEvent(node); AdditionEvent(node); } return holder; @@ -759,7 +757,7 @@ TrackNodePointer TrackList::Remove(Track *t) if ( !isNull( result ) ) RecalcPositions(result); - DeletionEvent(); + DeletionEvent(result); } } return result; @@ -912,7 +910,7 @@ void TrackList::SwapNodes(TrackNodePointer s1, TrackNodePointer s2) // Now correct the Index in the tracks, and other things RecalcPositions(s1); - PermutationEvent(); + PermutationEvent(s1); } bool TrackList::MoveUp(Track * t) @@ -1051,6 +1049,11 @@ void TrackList::ClearPendingTracks( ListOfTracks *pAdded ) if (pAdded) pAdded->clear(); + // To find the first node that remains after the first deleted one + TrackNodePointer node; + bool findingNode = false; + bool foundNode = false; + for (auto it = ListOfTracks::begin(), stop = ListOfTracks::end(); it != stop;) { if (it->get()->GetId() == TrackId{}) { @@ -1058,13 +1061,23 @@ void TrackList::ClearPendingTracks( ListOfTracks *pAdded ) pAdded->push_back( *it ); (*it)->SetOwner( {}, {} ); it = erase( it ); + + if (!findingNode) + findingNode = true; + if (!foundNode && it != stop) + node = (*it)->GetNode(); } - else + else { + if ( findingNode ) + foundNode = true; ++it; + } } - if (!empty()) + if (!empty()) { RecalcPositions(getBegin()); + DeletionEvent( node ); + } } bool TrackList::ApplyPendingTracks() @@ -1125,7 +1138,9 @@ bool TrackList::ApplyPendingTracks() } } if (inserted) { - RecalcPositions({first, this}); + TrackNodePointer node{first, this}; + RecalcPositions(node); + AdditionEvent(node); result = true; } diff --git a/src/Track.h b/src/Track.h index 321124153..7675fd3bc 100644 --- a/src/Track.h +++ b/src/Track.h @@ -1092,6 +1092,7 @@ wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); // Posted when tracks are reordered but otherwise unchanged. +// mpTrack points to the moved track that is earliest in the New ordering. wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, EVT_TRACKLIST_PERMUTED, TrackListEvent); @@ -1105,7 +1106,8 @@ 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 +// Also posted when one track replaces another. +// mpTrack points to the first track after the deletion, if there is one. wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, EVT_TRACKLIST_DELETION, TrackListEvent); @@ -1487,9 +1489,9 @@ private: void RecalcPositions(TrackNodePointer node); void SelectionEvent( const std::shared_ptr &pTrack ); - void PermutationEvent(); + void PermutationEvent(TrackNodePointer node); void DataEvent( const std::shared_ptr &pTrack, int code ); - void DeletionEvent(); + void DeletionEvent(TrackNodePointer node = {}); void AdditionEvent(TrackNodePointer node); void ResizingEvent(TrackNodePointer node); diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index bdf9ae3dd..d1924434f 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -14,6 +14,9 @@ Paul Licameli split from TrackPanel.cpp #include "TrackControls.h" #include "../../TrackPanelResizerCell.h" +#include "../../ClientData.h" +#include "../../Project.h" + TrackView::~TrackView() { } @@ -45,7 +48,7 @@ void TrackView::Copy( const TrackView &other ) { mMinimized = other.mMinimized; - // Let mY remain 0 -- TrackList::RecalcPositions corrects it later + // Let mY remain 0 -- TrackPositioner corrects it later mY = 0; mHeight = other.mHeight; } @@ -152,3 +155,53 @@ void TrackView::DoSetHeight(int h) { mHeight = h; } + +namespace { + +// Attach an object to each project. It receives track list events and updates +// track Y coordinates +struct TrackPositioner : ClientData::Base, wxEvtHandler +{ + AudacityProject &mProject; + + explicit TrackPositioner( AudacityProject &project ) + : mProject{ project } + { + TrackList::Get( project ).Bind( + EVT_TRACKLIST_ADDITION, &TrackPositioner::OnUpdate, this ); + TrackList::Get( project ).Bind( + EVT_TRACKLIST_DELETION, &TrackPositioner::OnUpdate, this ); + TrackList::Get( project ).Bind( + EVT_TRACKLIST_PERMUTED, &TrackPositioner::OnUpdate, this ); + TrackList::Get( project ).Bind( + EVT_TRACKLIST_RESIZING, &TrackPositioner::OnUpdate, this ); + } + + void OnUpdate( TrackListEvent & e ) + { + e.Skip(); + + auto iter = + TrackList::Get( mProject ).Find( e.mpTrack.lock().get() ); + if ( !*iter ) + return; + + auto prev = iter; + auto yy = TrackView::GetCumulativeHeight( *--prev ); + + while( auto pTrack = *iter ) { + auto &view = TrackView::Get( *pTrack ); + view.SetY( yy ); + yy += view.GetHeight(); + ++iter; + } + } +}; + +static const AudacityProject::AttachedObjects::RegisteredFactory key{ + []( AudacityProject &project ){ + return std::make_shared< TrackPositioner >( project ); + } +}; + +} From 3f1fd8ced0fb5fe617ad2dd7808cd1ae2ca2c0f3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 10:27:04 -0400 Subject: [PATCH 3/6] TrackView handles its own special XML attributes via virtual functions --- src/Track.cpp | 23 +++++++++-------------- src/tracks/ui/CommonTrackPanelCell.cpp | 9 +++++++++ src/tracks/ui/CommonTrackPanelCell.h | 7 +++++++ src/tracks/ui/TrackView.cpp | 26 ++++++++++++++++++++++++++ src/tracks/ui/TrackView.h | 3 +++ 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 4778b1d70..6e77df7f9 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -1191,9 +1191,10 @@ void Track::WriteCommonXMLAttributes( xmlFile.WriteAttr(wxT("name"), GetName()); xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected()); } - auto &view = TrackView::Get( *this ); - xmlFile.WriteAttr(wxT("height"), view.GetActualHeight()); - xmlFile.WriteAttr(wxT("minimized"), view.GetMinimized()); + if ( mpView ) + mpView->WriteXMLAttributes( xmlFile ); + if ( mpControls ) + mpControls->WriteXMLAttributes( xmlFile ); } // Return true iff the attribute is recognized. @@ -1201,21 +1202,15 @@ bool Track::HandleCommonXMLAttribute(const wxChar *attr, const wxChar *value) { long nValue = -1; wxString strValue( value ); - if (!wxStrcmp(attr, wxT("name")) && + if ( mpView && mpView->HandleXMLAttribute( attr, value ) ) + ; + else if ( mpControls && mpControls->HandleXMLAttribute( attr, value ) ) + ; + else if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue)) { SetName( strValue ); return true; } - else if (!wxStrcmp(attr, wxT("height")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { - TrackView::Get( *this ).SetHeight(nValue); - return true; - } - else if (!wxStrcmp(attr, wxT("minimized")) && - XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { - TrackView::Get( *this ).SetMinimized(nValue != 0); - return true; - } else if (!wxStrcmp(attr, wxT("isSelected")) && XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { this->SetSelected(nValue != 0); diff --git a/src/tracks/ui/CommonTrackPanelCell.cpp b/src/tracks/ui/CommonTrackPanelCell.cpp index 5c3caeb26..e3b280e6f 100644 --- a/src/tracks/ui/CommonTrackPanelCell.cpp +++ b/src/tracks/ui/CommonTrackPanelCell.cpp @@ -66,3 +66,12 @@ std::shared_ptr CommonTrackCell::DoFindTrack() { return mwTrack.lock(); } + +void CommonTrackCell::WriteXMLAttributes( XMLWriter & ) const +{ +} + +bool CommonTrackCell::HandleXMLAttribute( const wxChar *, const wxChar * ) +{ + return false; +} diff --git a/src/tracks/ui/CommonTrackPanelCell.h b/src/tracks/ui/CommonTrackPanelCell.h index a571624b5..ace3520fe 100644 --- a/src/tracks/ui/CommonTrackPanelCell.h +++ b/src/tracks/ui/CommonTrackPanelCell.h @@ -19,6 +19,7 @@ Paul Licameli split from TrackPanel.cpp #include class Track; +class XMLWriter; class AUDACITY_DLL_API CommonTrackPanelCell /* not final */ : public TrackPanelCell @@ -65,6 +66,12 @@ public: virtual void Reparent( const std::shared_ptr &parent ); + // default does nothing + virtual void WriteXMLAttributes( XMLWriter & ) const; + + // default recognizes no attributes, and returns false + virtual bool HandleXMLAttribute( const wxChar *attr, const wxChar *value ); + private: std::weak_ptr< Track > mwTrack; }; diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index d1924434f..0deb266c1 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -16,6 +16,8 @@ Paul Licameli split from TrackPanel.cpp #include "../../ClientData.h" #include "../../Project.h" +#include "../../xml/XMLTagHandler.h" +#include "../../xml/XMLWriter.h" TrackView::~TrackView() { @@ -74,6 +76,30 @@ void TrackView::SetMinimized(bool isMinimized) leader->AdjustPositions(); } +void TrackView::WriteXMLAttributes( XMLWriter &xmlFile ) const +{ + xmlFile.WriteAttr(wxT("height"), GetActualHeight()); + xmlFile.WriteAttr(wxT("minimized"), GetMinimized()); +} + +bool TrackView::HandleXMLAttribute( const wxChar *attr, const wxChar *value ) +{ + wxString strValue; + long nValue; + if (!wxStrcmp(attr, wxT("height")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + SetHeight(nValue); + return true; + } + else if (!wxStrcmp(attr, wxT("minimized")) && + XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) { + SetMinimized(nValue != 0); + return true; + } + else + return false; +} + void TrackView::DoSetMinimized(bool isMinimized) { mMinimized = isMinimized; diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index e1afaa32d..3c339c78b 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -69,6 +69,9 @@ public: std::shared_ptr GetResizer(); std::shared_ptr GetResizer() const; + void WriteXMLAttributes( XMLWriter & ) const override; + bool HandleXMLAttribute( const wxChar *attr, const wxChar *value ) override; + protected: virtual void DoSetMinimized( bool isMinimized ); From 8793d6b475fad20c2dad3832e98241a7b2315cc3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 10:43:55 -0400 Subject: [PATCH 4/6] Demote Copy to CommonTrackCell; Track points only to that base class --- src/Track.h | 6 +++--- src/tracks/labeltrack/ui/LabelTrackView.cpp | 2 +- src/tracks/labeltrack/ui/LabelTrackView.h | 2 +- src/tracks/ui/CommonTrackPanelCell.cpp | 4 ++++ src/tracks/ui/CommonTrackPanelCell.h | 3 +++ src/tracks/ui/TrackView.cpp | 15 ++++++++++----- src/tracks/ui/TrackView.h | 2 +- 7 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/Track.h b/src/Track.h index 7675fd3bc..edc82f986 100644 --- a/src/Track.h +++ b/src/Track.h @@ -263,8 +263,8 @@ class AUDACITY_DLL_API Track /* not final */ // Return another, associated TrackPanelCell object that implements // click and drag and keystrokes in the track contents. - std::shared_ptr GetTrackView(); - std::shared_ptr GetTrackView() const; + std::shared_ptr GetTrackView(); + std::shared_ptr GetTrackView() const; // Return another, associated TrackPanelCell object that implements the // drop-down, close and minimize buttons, etc. @@ -704,7 +704,7 @@ public: bool HandleCommonXMLAttribute(const wxChar *attr, const wxChar *value); protected: - std::shared_ptr mpView; + std::shared_ptr mpView; std::shared_ptr mpControls; }; diff --git a/src/tracks/labeltrack/ui/LabelTrackView.cpp b/src/tracks/labeltrack/ui/LabelTrackView.cpp index 620a22e87..2550ed99b 100644 --- a/src/tracks/labeltrack/ui/LabelTrackView.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackView.cpp @@ -97,7 +97,7 @@ void LabelTrackView::UnbindFrom( LabelTrack *pParent ) EVT_LABELTRACK_PERMUTED, &LabelTrackView::OnLabelPermuted, this ); } -void LabelTrackView::Copy( const TrackView &other ) +void LabelTrackView::Copy( const CommonTrackCell &other ) { TrackView::Copy( other ); diff --git a/src/tracks/labeltrack/ui/LabelTrackView.h b/src/tracks/labeltrack/ui/LabelTrackView.h index 4a25aabb7..dbcb631cb 100644 --- a/src/tracks/labeltrack/ui/LabelTrackView.h +++ b/src/tracks/labeltrack/ui/LabelTrackView.h @@ -82,7 +82,7 @@ private: std::shared_ptr DoGetVRulerControls() override; // Preserve some view state too for undo/redo purposes - void Copy( const TrackView &other ) override; + void Copy( const CommonTrackCell &other ) override; public: static void DoEditLabels( diff --git a/src/tracks/ui/CommonTrackPanelCell.cpp b/src/tracks/ui/CommonTrackPanelCell.cpp index e3b280e6f..e0ac5ff8f 100644 --- a/src/tracks/ui/CommonTrackPanelCell.cpp +++ b/src/tracks/ui/CommonTrackPanelCell.cpp @@ -57,6 +57,10 @@ CommonTrackCell::CommonTrackCell( const std::shared_ptr< Track > &parent ) CommonTrackCell::~CommonTrackCell() = default; +void CommonTrackCell::Copy( const CommonTrackCell & ) +{ +} + void CommonTrackCell::Reparent( const std::shared_ptr &parent ) { mwTrack = parent; diff --git a/src/tracks/ui/CommonTrackPanelCell.h b/src/tracks/ui/CommonTrackPanelCell.h index ace3520fe..a2db5d54d 100644 --- a/src/tracks/ui/CommonTrackPanelCell.h +++ b/src/tracks/ui/CommonTrackPanelCell.h @@ -62,6 +62,9 @@ public: ~CommonTrackCell(); + // Copy state, for undo/redo purposes + virtual void Copy( const CommonTrackCell &other ); + std::shared_ptr DoFindTrack() override; virtual void Reparent( const std::shared_ptr &parent ); diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index 0deb266c1..7e6080827 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -46,8 +46,13 @@ int TrackView::GetTotalHeight( const TrackList &list ) return GetCumulativeHeight( *list.Any().rbegin() ); } -void TrackView::Copy( const TrackView &other ) +void TrackView::Copy( const CommonTrackCell &otherCell ) { + auto pOther = dynamic_cast< const TrackView* >( &otherCell ); + if ( !pOther ) + return; + auto &other = *pOther; + mMinimized = other.mMinimized; // Let mY remain 0 -- TrackPositioner corrects it later @@ -57,12 +62,12 @@ void TrackView::Copy( const TrackView &other ) TrackView &TrackView::Get( Track &track ) { - return *track.GetTrackView(); + return static_cast( *track.GetTrackView() ); } const TrackView &TrackView::Get( const Track &track ) { - return *track.GetTrackView(); + return static_cast( *track.GetTrackView() ); } void TrackView::SetMinimized(bool isMinimized) @@ -105,7 +110,7 @@ void TrackView::DoSetMinimized(bool isMinimized) mMinimized = isMinimized; } -std::shared_ptr Track::GetTrackView() +std::shared_ptr Track::GetTrackView() { if (!mpView) // create on demand @@ -113,7 +118,7 @@ std::shared_ptr Track::GetTrackView() return mpView; } -std::shared_ptr Track::GetTrackView() const +std::shared_ptr Track::GetTrackView() const { return const_cast(this)->GetTrackView(); } diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index 3c339c78b..0a57decae 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -42,7 +42,7 @@ public: static int GetTotalHeight( const TrackList &list ); // Copy view state, for undo/redo purposes - virtual void Copy( const TrackView &other ); + void Copy( const CommonTrackCell &other ) override; static TrackView &Get( Track & ); static const TrackView &Get( const Track & ); From dc9e436dde54381582635dc8c015b3016f805ae4 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 11:02:55 -0400 Subject: [PATCH 5/6] Change the track view copy function... ... It is const, renamed CopyTo, and invokes the create-on-demand factory in the destination track; this means Track.cpp doesn't need to do that, and so does not need TrackView.h --- src/Track.cpp | 4 +--- src/tracks/labeltrack/ui/LabelTrackView.cpp | 7 ++++--- src/tracks/labeltrack/ui/LabelTrackView.h | 2 +- src/tracks/ui/CommonTrackPanelCell.cpp | 2 +- src/tracks/ui/CommonTrackPanelCell.h | 3 ++- src/tracks/ui/TrackView.cpp | 13 +++++-------- src/tracks/ui/TrackView.h | 2 +- 7 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index 6e77df7f9..e3a78a8d4 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -41,8 +41,6 @@ and TimeTrack. #include "InconsistencyException.h" -#include "tracks/ui/TrackView.h" - #ifdef _MSC_VER //Disable truncation warnings #pragma warning( disable : 4786 ) @@ -115,7 +113,7 @@ Track::Holder Track::Duplicate() const if (mpView) // Copy view state that might be important to undo/redo - TrackView::Get( *result ).Copy( *mpView ); + mpView->CopyTo( *result ); return result; } diff --git a/src/tracks/labeltrack/ui/LabelTrackView.cpp b/src/tracks/labeltrack/ui/LabelTrackView.cpp index 2550ed99b..12c75c127 100644 --- a/src/tracks/labeltrack/ui/LabelTrackView.cpp +++ b/src/tracks/labeltrack/ui/LabelTrackView.cpp @@ -97,13 +97,14 @@ void LabelTrackView::UnbindFrom( LabelTrack *pParent ) EVT_LABELTRACK_PERMUTED, &LabelTrackView::OnLabelPermuted, this ); } -void LabelTrackView::Copy( const CommonTrackCell &other ) +void LabelTrackView::CopyTo( Track &track ) const { - TrackView::Copy( other ); + TrackView::CopyTo( track ); + auto &other = TrackView::Get( track ); if ( const auto pOther = dynamic_cast< const LabelTrackView* >( &other ) ) { // only one field is important to preserve in undo/redo history - mSelIndex = pOther->mSelIndex; + pOther->mSelIndex = mSelIndex; } } diff --git a/src/tracks/labeltrack/ui/LabelTrackView.h b/src/tracks/labeltrack/ui/LabelTrackView.h index dbcb631cb..39376d28d 100644 --- a/src/tracks/labeltrack/ui/LabelTrackView.h +++ b/src/tracks/labeltrack/ui/LabelTrackView.h @@ -82,7 +82,7 @@ private: std::shared_ptr DoGetVRulerControls() override; // Preserve some view state too for undo/redo purposes - void Copy( const CommonTrackCell &other ) override; + void CopyTo( Track &track ) const override; public: static void DoEditLabels( diff --git a/src/tracks/ui/CommonTrackPanelCell.cpp b/src/tracks/ui/CommonTrackPanelCell.cpp index e0ac5ff8f..f34fafe78 100644 --- a/src/tracks/ui/CommonTrackPanelCell.cpp +++ b/src/tracks/ui/CommonTrackPanelCell.cpp @@ -57,7 +57,7 @@ CommonTrackCell::CommonTrackCell( const std::shared_ptr< Track > &parent ) CommonTrackCell::~CommonTrackCell() = default; -void CommonTrackCell::Copy( const CommonTrackCell & ) +void CommonTrackCell::CopyTo( Track& ) const { } diff --git a/src/tracks/ui/CommonTrackPanelCell.h b/src/tracks/ui/CommonTrackPanelCell.h index a2db5d54d..b229a4c60 100644 --- a/src/tracks/ui/CommonTrackPanelCell.h +++ b/src/tracks/ui/CommonTrackPanelCell.h @@ -63,7 +63,8 @@ public: ~CommonTrackCell(); // Copy state, for undo/redo purposes - virtual void Copy( const CommonTrackCell &other ); + // The default does nothing + virtual void CopyTo( Track &track ) const; std::shared_ptr DoFindTrack() override; diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index 7e6080827..47524c25f 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -46,18 +46,15 @@ int TrackView::GetTotalHeight( const TrackList &list ) return GetCumulativeHeight( *list.Any().rbegin() ); } -void TrackView::Copy( const CommonTrackCell &otherCell ) +void TrackView::CopyTo( Track &track ) const { - auto pOther = dynamic_cast< const TrackView* >( &otherCell ); - if ( !pOther ) - return; - auto &other = *pOther; + auto &other = Get( track ); - mMinimized = other.mMinimized; + other.mMinimized = mMinimized; // Let mY remain 0 -- TrackPositioner corrects it later - mY = 0; - mHeight = other.mHeight; + other.mY = 0; + other.mHeight = mHeight; } TrackView &TrackView::Get( Track &track ) diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index 0a57decae..0feee6c35 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -42,7 +42,7 @@ public: static int GetTotalHeight( const TrackList &list ); // Copy view state, for undo/redo purposes - void Copy( const CommonTrackCell &other ) override; + void CopyTo( Track &track ) const override; static TrackView &Get( Track & ); static const TrackView &Get( const Track & ); From 9e731390f65e5c810ea5563df432195a956bca7a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 22 Jun 2019 11:27:54 -0400 Subject: [PATCH 6/6] Don't define any Track members outside of Track.cpp --- src/Track.cpp | 30 ++++++++++++++++--------- src/Track.h | 36 +++++++----------------------- src/tracks/ui/TrackControls.cpp | 13 +++++++++-- src/tracks/ui/TrackControls.h | 11 ++++++++++ src/tracks/ui/TrackView.cpp | 39 ++++++++++----------------------- src/tracks/ui/TrackView.h | 11 ++++++++++ 6 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/Track.cpp b/src/Track.cpp index e3a78a8d4..9a4d50cd3 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -138,6 +138,26 @@ void Track::SetOwner mNode = node; } +const std::shared_ptr &Track::GetTrackView() +{ + return mpView; +} + +void Track::SetTrackView( const std::shared_ptr &pView ) +{ + mpView = pView; +} + +const std::shared_ptr &Track::GetTrackControls() +{ + return mpControls; +} + +void Track::SetTrackControls( const std::shared_ptr &pControls ) +{ + mpControls = pControls; +} + int Track::GetIndex() const { return mIndex; @@ -1270,13 +1290,3 @@ void TrackFactory::Destroy( AudacityProject &project ) { project.AttachedObjects::Assign( key2, nullptr ); } - -template<> auto DoGetControls::Implementation() -> Function { - return nullptr; -} -static DoGetControls registerDoGetControls; - -template<> auto DoGetView::Implementation() -> Function { - return nullptr; -} -static DoGetView registerDoGetView; diff --git a/src/Track.h b/src/Track.h index edc82f986..d850a983a 100644 --- a/src/Track.h +++ b/src/Track.h @@ -261,15 +261,15 @@ class AUDACITY_DLL_API Track /* not final */ public: mutable wxSize vrulerSize; - // Return another, associated TrackPanelCell object that implements - // click and drag and keystrokes in the track contents. - std::shared_ptr GetTrackView(); - std::shared_ptr GetTrackView() const; + // These are exposed only for the purposes of the TrackView class, to + // initialize the pointer on demand + const std::shared_ptr &GetTrackView(); + void SetTrackView( const std::shared_ptr &pView ); - // Return another, associated TrackPanelCell object that implements the - // drop-down, close and minimize buttons, etc. - std::shared_ptr GetTrackControls(); - std::shared_ptr GetTrackControls() const; + // These are exposed only for the purposes of the TrackControls class, to + // initialize the pointer on demand + const std::shared_ptr &GetTrackControls(); + void SetTrackControls( const std::shared_ptr &pControls ); // Return another, associated TrackPanelCell object that implements the @@ -1588,24 +1588,4 @@ class AUDACITY_DLL_API TrackFactory final #endif }; -#include "AttachedVirtualFunction.h" - -struct DoGetControlsTag; - -using DoGetControls = -AttachedVirtualFunction< - DoGetControlsTag, - std::shared_ptr< TrackControls >, - Track ->; - -struct DoGetViewTag; - -using DoGetView = -AttachedVirtualFunction< - DoGetViewTag, - std::shared_ptr< TrackView >, - Track ->; - #endif diff --git a/src/tracks/ui/TrackControls.cpp b/src/tracks/ui/TrackControls.cpp index 0c850ec59..5e4dee257 100644 --- a/src/tracks/ui/TrackControls.cpp +++ b/src/tracks/ui/TrackControls.cpp @@ -24,11 +24,20 @@ TrackControls::~TrackControls() TrackControls &TrackControls::Get( Track &track ) { - return *static_cast( track.GetTrackControls().get() ); + auto pControls = + std::static_pointer_cast( track.GetTrackControls() ); + if (!pControls) + // create on demand + track.SetTrackControls( pControls = DoGetControls::Call( track ) ); + return *pControls; } const TrackControls &TrackControls::Get( const Track &track ) { - return *static_cast( track.GetTrackControls().get() ); + return Get( const_cast< Track& >( track ) ); } +template<> auto DoGetControls::Implementation() -> Function { + return nullptr; +} +static DoGetControls registerDoGetControls; diff --git a/src/tracks/ui/TrackControls.h b/src/tracks/ui/TrackControls.h index 317548343..11f451bc6 100644 --- a/src/tracks/ui/TrackControls.h +++ b/src/tracks/ui/TrackControls.h @@ -28,4 +28,15 @@ public: virtual ~TrackControls() = 0; }; +#include "AttachedVirtualFunction.h" + +struct DoGetControlsTag; + +using DoGetControls = +AttachedVirtualFunction< + DoGetControlsTag, + std::shared_ptr< TrackControls >, + Track +>; + #endif diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index 47524c25f..7d25afe14 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -59,12 +59,16 @@ void TrackView::CopyTo( Track &track ) const TrackView &TrackView::Get( Track &track ) { - return static_cast( *track.GetTrackView() ); + auto pView = std::static_pointer_cast( track.GetTrackView() ); + if (!pView) + // create on demand + track.SetTrackView( pView = DoGetView::Call( track ) ); + return *pView; } const TrackView &TrackView::Get( const Track &track ) { - return static_cast( *track.GetTrackView() ); + return Get( const_cast< Track& >( track ) ); } void TrackView::SetMinimized(bool isMinimized) @@ -107,32 +111,6 @@ void TrackView::DoSetMinimized(bool isMinimized) mMinimized = isMinimized; } -std::shared_ptr Track::GetTrackView() -{ - if (!mpView) - // create on demand - mpView = DoGetView::Call( *this ); - return mpView; -} - -std::shared_ptr Track::GetTrackView() const -{ - return const_cast(this)->GetTrackView(); -} - -std::shared_ptr Track::GetTrackControls() -{ - if (!mpControls) - // create on demand - mpControls = DoGetControls::Call( *this ); - return mpControls; -} - -std::shared_ptr Track::GetTrackControls() const -{ - return const_cast< Track* >( this )->GetTrackControls(); -} - std::shared_ptr TrackView::GetVRulerControls() { if (!mpVRulerControls) @@ -233,3 +211,8 @@ static const AudacityProject::AttachedObjects::RegisteredFactory key{ }; } + +template<> auto DoGetView::Implementation() -> Function { + return nullptr; +} +static DoGetView registerDoGetView; diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index 0feee6c35..fcf855b15 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -93,4 +93,15 @@ private: int mHeight{ DefaultHeight }; }; +#include "AttachedVirtualFunction.h" + +struct DoGetViewTag; + +using DoGetView = +AttachedVirtualFunction< + DoGetViewTag, + std::shared_ptr< TrackView >, + Track +>; + #endif