1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 TrackView.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "TrackView.h"
12 #include "../../Track.h"
13 
14 #include "ClientData.h"
15 #include "Project.h"
16 #include "XMLTagHandler.h"
17 #include "XMLWriter.h"
18 
TrackView(const std::shared_ptr<Track> & pTrack)19 TrackView::TrackView( const std::shared_ptr<Track> &pTrack )
20    : CommonTrackCell{ pTrack }
21 {
22    DoSetHeight( GetDefaultTrackHeight::Call( *pTrack ) );
23 }
24 
~TrackView()25 TrackView::~TrackView()
26 {
27 }
28 
GetTrackHeight(const Track * pTrack)29 int TrackView::GetTrackHeight( const Track *pTrack )
30 {
31    return pTrack ? Get( *pTrack ).GetHeight() : 0;
32 }
33 
GetChannelGroupHeight(const Track * pTrack)34 int TrackView::GetChannelGroupHeight( const Track *pTrack )
35 {
36    return pTrack ? TrackList::Channels( pTrack ).sum( GetTrackHeight ) : 0;
37 }
38 
GetCumulativeHeight(const Track * pTrack)39 int TrackView::GetCumulativeHeight( const Track *pTrack )
40 {
41    if ( !pTrack )
42       return 0;
43    auto &view = Get( *pTrack );
44    return view.GetCumulativeHeightBefore() + view.GetHeight();
45 }
46 
GetTotalHeight(const TrackList & list)47 int TrackView::GetTotalHeight( const TrackList &list )
48 {
49    return GetCumulativeHeight( *list.Any().rbegin() );
50 }
51 
CopyTo(Track & track) const52 void TrackView::CopyTo( Track &track ) const
53 {
54    auto &other = Get( track );
55 
56    other.mMinimized = mMinimized;
57 
58    // Let mY remain 0 -- TrackPositioner corrects it later
59    other.mY = 0;
60    other.mHeight = mHeight;
61 }
62 
Get(Track & track)63 TrackView &TrackView::Get( Track &track )
64 {
65    auto pView = std::static_pointer_cast<TrackView>( track.GetTrackView() );
66    if (!pView)
67       // create on demand
68       track.SetTrackView( pView = DoGetView::Call( track ) );
69    return *pView;
70 }
71 
Get(const Track & track)72 const TrackView &TrackView::Get( const Track &track )
73 {
74    return Get( const_cast< Track& >( track ) );
75 }
76 
SetMinimized(bool isMinimized)77 void TrackView::SetMinimized(bool isMinimized)
78 {
79    // Do special changes appropriate to subclass
80    DoSetMinimized(isMinimized);
81 
82    // Update positions and heights starting from the first track in the group
83    auto leader = *TrackList::Channels( FindTrack().get() ).begin();
84    if ( leader )
85       leader->AdjustPositions();
86 }
87 
WriteXMLAttributes(XMLWriter & xmlFile) const88 void TrackView::WriteXMLAttributes( XMLWriter &xmlFile ) const
89 {
90    xmlFile.WriteAttr(wxT("height"), GetExpandedHeight());
91    xmlFile.WriteAttr(wxT("minimized"), GetMinimized());
92 }
93 
HandleXMLAttribute(const std::string_view & attr,const XMLAttributeValueView & valueView)94 bool TrackView::HandleXMLAttribute(
95    const std::string_view& attr, const XMLAttributeValueView& valueView)
96 {
97    long nValue;
98 
99    if (attr == "height" && valueView.TryGet(nValue)) {
100       // Bug 2803: Extreme values for track height (caused by integer overflow)
101       // will stall Audacity as it tries to create an enormous vertical ruler.
102       // So clamp to reasonable values.
103       nValue = std::max( 40l, std::min( nValue, 1000l ));
104       SetExpandedHeight(nValue);
105       return true;
106    }
107    else if ( attr == "minimized" && valueView.TryGet(nValue)) {
108       SetMinimized(nValue != 0);
109       return true;
110    }
111    else
112       return false;
113 }
114 
GetSubViews(const wxRect & rect)115 auto TrackView::GetSubViews( const wxRect &rect ) -> Refinement
116 {
117    return { { rect.GetTop(), shared_from_this() } };
118 }
119 
IsSpectral() const120 bool TrackView::IsSpectral() const
121 {
122    return false;
123 }
124 
DoSetMinimized(bool isMinimized)125 void TrackView::DoSetMinimized(bool isMinimized)
126 {
127    mMinimized = isMinimized;
128 }
129 
GetVRulerControls()130 std::shared_ptr<TrackVRulerControls> TrackView::GetVRulerControls()
131 {
132    if (!mpVRulerControls)
133       // create on demand
134       mpVRulerControls = DoGetVRulerControls();
135    return mpVRulerControls;
136 }
137 
GetVRulerControls() const138 std::shared_ptr<const TrackVRulerControls> TrackView::GetVRulerControls() const
139 {
140    return const_cast< TrackView* >( this )->GetVRulerControls();
141 }
142 
DoSetY(int y)143 void TrackView::DoSetY(int y)
144 {
145    mY = y;
146 }
147 
GetHeight() const148 int TrackView::GetHeight() const
149 {
150    if ( GetMinimized() )
151       return GetMinimizedHeight();
152 
153    return mHeight;
154 }
155 
SetExpandedHeight(int h)156 void TrackView::SetExpandedHeight(int h)
157 {
158    DoSetHeight(h);
159    FindTrack()->AdjustPositions();
160 }
161 
DoSetHeight(int h)162 void TrackView::DoSetHeight(int h)
163 {
164    mHeight = h;
165 }
166 
GetAffordanceControls()167 std::shared_ptr<CommonTrackCell> TrackView::GetAffordanceControls()
168 {
169    return {};
170 }
171 
172 namespace {
173 
174 /*!
175  Attached to each project, it receives track list events and maintains the
176  cache of cumulative track view heights for use by TrackPanel.
177  */
178 struct TrackPositioner final : ClientData::Base, wxEvtHandler
179 {
180    AudacityProject &mProject;
181 
TrackPositioner__anon35fae38e0111::TrackPositioner182    explicit TrackPositioner( AudacityProject &project )
183       : mProject{ project }
184    {
185       TrackList::Get( project ).Bind(
186          EVT_TRACKLIST_ADDITION, &TrackPositioner::OnUpdate, this );
187       TrackList::Get( project ).Bind(
188          EVT_TRACKLIST_DELETION, &TrackPositioner::OnUpdate, this );
189       TrackList::Get( project ).Bind(
190          EVT_TRACKLIST_PERMUTED, &TrackPositioner::OnUpdate, this );
191       TrackList::Get( project ).Bind(
192          EVT_TRACKLIST_RESIZING, &TrackPositioner::OnUpdate, this );
193    }
194    TrackPositioner( const TrackPositioner & ) PROHIBITED;
195    TrackPositioner &operator=( const TrackPositioner & ) PROHIBITED;
196 
OnUpdate__anon35fae38e0111::TrackPositioner197    void OnUpdate( TrackListEvent & e )
198    {
199       e.Skip();
200 
201       auto iter =
202          TrackList::Get( mProject ).Find( e.mpTrack.lock().get() );
203       if ( !*iter )
204          return;
205 
206       auto prev = iter;
207       auto yy = TrackView::GetCumulativeHeight( *--prev );
208 
209       while( auto pTrack = *iter ) {
210          auto &view = TrackView::Get( *pTrack );
211          view.SetCumulativeHeightBefore( yy );
212          yy += view.GetHeight();
213          ++iter;
214       }
215    }
216 };
217 
218 static const AudacityProject::AttachedObjects::RegisteredFactory key{
__anon35fae38e0202( )219   []( AudacityProject &project ){
220      return std::make_shared< TrackPositioner >( project );
221    }
222 };
223 
224 }
225 
DEFINE_ATTACHED_VIRTUAL(DoGetView)226 DEFINE_ATTACHED_VIRTUAL(DoGetView) {
227    return nullptr;
228 }
229 
DEFINE_ATTACHED_VIRTUAL(GetDefaultTrackHeight)230 DEFINE_ATTACHED_VIRTUAL(GetDefaultTrackHeight) {
231    return nullptr;
232 }
233