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