1 /**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 PlayableTrackControls.cpp
6
7 Paul Licameli split from TrackInfo.cpp
8
9 **********************************************************************/
10
11 #include "PlayableTrackControls.h"
12
13
14
15 #include "PlayableTrackButtonHandles.h"
16 #include "AColor.h"
17 #include "../../../Track.h"
18 #include "../../../TrackInfo.h"
19 #include "../../../TrackPanelDrawingContext.h"
20 #include "ViewInfo.h"
21
22 #include <wx/dc.h>
23
24 using TCPLine = TrackInfo::TCPLine;
25
26 namespace {
27
GetNarrowMuteHorizontalBounds(const wxRect & rect,wxRect & dest)28 void GetNarrowMuteHorizontalBounds( const wxRect & rect, wxRect &dest )
29 {
30 dest.x = rect.x;
31 dest.width = rect.width / 2 + 1;
32 }
33
GetNarrowSoloHorizontalBounds(const wxRect & rect,wxRect & dest)34 void GetNarrowSoloHorizontalBounds( const wxRect & rect, wxRect &dest )
35 {
36 wxRect muteRect;
37 GetNarrowMuteHorizontalBounds( rect, muteRect );
38 dest.x = rect.x + muteRect.width;
39 dest.width = rect.width - muteRect.width + TitleSoloBorderOverlap;
40 }
41
GetWideMuteSoloHorizontalBounds(const wxRect & rect,wxRect & dest)42 void GetWideMuteSoloHorizontalBounds( const wxRect & rect, wxRect &dest )
43 {
44 // Larger button, symmetrically placed intended.
45 // On windows this gives 15 pixels each side.
46 dest.width = rect.width - 2 * kTrackInfoBtnSize + 6;
47 dest.x = rect.x + kTrackInfoBtnSize -3;
48 }
49
MuteOrSoloDrawFunction(wxDC * dc,const wxRect & bev,const Track * pTrack,bool down,bool WXUNUSED (captured),bool solo,bool hit)50 void MuteOrSoloDrawFunction
51 ( wxDC *dc, const wxRect &bev, const Track *pTrack, bool down,
52 bool WXUNUSED(captured),
53 bool solo, bool hit )
54 {
55 //bev.Inflate(-1, -1);
56 bool selected = pTrack ? pTrack->GetSelected() : true;
57 auto pt = dynamic_cast<const PlayableTrack *>(pTrack);
58 bool value = pt ? (solo ? pt->GetSolo() : pt->GetMute()) : false;
59
60 #if 0
61 AColor::MediumTrackInfo( dc, t->GetSelected());
62 if( solo )
63 {
64 if( pt && pt->GetSolo() )
65 {
66 AColor::Solo(dc, pt->GetSolo(), t->GetSelected());
67 }
68 }
69 else
70 {
71 if( pt && pt->GetMute() )
72 {
73 AColor::Mute(dc, pt->GetMute(), t->GetSelected(), pt->GetSolo());
74 }
75 }
76 //(solo) ? AColor::Solo(dc, t->GetSolo(), t->GetSelected()) :
77 // AColor::Mute(dc, t->GetMute(), t->GetSelected(), t->GetSolo());
78 dc->SetPen( *wxTRANSPARENT_PEN );//No border!
79 dc->DrawRectangle(bev);
80 #endif
81
82 wxCoord textWidth, textHeight;
83 wxString str = (solo) ?
84 /* i18n-hint: This is on a button that will silence all the other tracks.*/
85 _("Solo") :
86 /* i18n-hint: This is on a button that will silence this track.*/
87 _("Mute");
88
89 AColor::Bevel2(
90 *dc,
91 value == down,
92 bev,
93 selected, hit
94 );
95
96 TrackInfo::SetTrackInfoFont(dc);
97 dc->GetTextExtent(str, &textWidth, &textHeight);
98 dc->DrawText(str, bev.x + (bev.width - textWidth) / 2, bev.y + (bev.height - textHeight) / 2);
99 }
100
WideMuteDrawFunction(TrackPanelDrawingContext & context,const wxRect & rect,const Track * pTrack)101 void WideMuteDrawFunction
102 ( TrackPanelDrawingContext &context,
103 const wxRect &rect, const Track *pTrack )
104 {
105 auto dc = &context.dc;
106 wxRect bev = rect;
107 GetWideMuteSoloHorizontalBounds( rect, bev );
108 auto target = dynamic_cast<MuteButtonHandle*>( context.target.get() );
109 bool hit = target && target->GetTrack().get() == pTrack;
110 bool captured = hit && target->IsClicked();
111 bool down = captured && bev.Contains( context.lastState.GetPosition());
112 MuteOrSoloDrawFunction( dc, bev, pTrack, down, captured, false, hit );
113 }
114
WideSoloDrawFunction(TrackPanelDrawingContext & context,const wxRect & rect,const Track * pTrack)115 void WideSoloDrawFunction
116 ( TrackPanelDrawingContext &context,
117 const wxRect &rect, const Track *pTrack )
118 {
119 auto dc = &context.dc;
120 wxRect bev = rect;
121 GetWideMuteSoloHorizontalBounds( rect, bev );
122 auto target = dynamic_cast<SoloButtonHandle*>( context.target.get() );
123 bool hit = target && target->GetTrack().get() == pTrack;
124 bool captured = hit && target->IsClicked();
125 bool down = captured && bev.Contains( context.lastState.GetPosition());
126 MuteOrSoloDrawFunction( dc, bev, pTrack, down, captured, true, hit );
127 }
128
MuteAndSoloDrawFunction(TrackPanelDrawingContext & context,const wxRect & rect,const Track * pTrack)129 void MuteAndSoloDrawFunction
130 ( TrackPanelDrawingContext &context,
131 const wxRect &rect, const Track *pTrack )
132 {
133 auto dc = &context.dc;
134 bool bHasSoloButton = TrackInfo::HasSoloButton();
135
136 wxRect bev = rect;
137 if ( bHasSoloButton )
138 GetNarrowMuteHorizontalBounds( rect, bev );
139 else
140 GetWideMuteSoloHorizontalBounds( rect, bev );
141 {
142 auto target = dynamic_cast<MuteButtonHandle*>( context.target.get() );
143 bool hit = target && target->GetTrack().get() == pTrack;
144 bool captured = hit && target->IsClicked();
145 bool down = captured && bev.Contains( context.lastState.GetPosition());
146 MuteOrSoloDrawFunction( dc, bev, pTrack, down, captured, false, hit );
147 }
148
149 if( !bHasSoloButton )
150 return;
151
152 GetNarrowSoloHorizontalBounds( rect, bev );
153 {
154 auto target = dynamic_cast<SoloButtonHandle*>( context.target.get() );
155 bool hit = target && target->GetTrack().get() == pTrack;
156 bool captured = hit && target->IsClicked();
157 bool down = captured && bev.Contains( context.lastState.GetPosition());
158 MuteOrSoloDrawFunction( dc, bev, pTrack, down, captured, true, hit );
159 }
160 }
161 }
162
GetMuteSoloRect(const wxRect & rect,wxRect & dest,bool solo,bool bHasSoloButton,const Track * pTrack)163 void PlayableTrackControls::GetMuteSoloRect
164 (const wxRect & rect, wxRect & dest, bool solo, bool bHasSoloButton,
165 const Track *pTrack)
166 {
167 auto &trackControl = static_cast<const CommonTrackControls&>(
168 TrackControls::Get( *pTrack ) );
169 auto resultsM = TrackInfo::CalcItemY( trackControl.GetTCPLines(), TCPLine::kItemMute );
170 auto resultsS = TrackInfo::CalcItemY( trackControl.GetTCPLines(), TCPLine::kItemSolo );
171 dest.height = resultsS.second;
172
173 int yMute = resultsM.first;
174 int ySolo = resultsS.first;
175
176 bool bSameRow = ( yMute == ySolo );
177 bool bNarrow = bSameRow && bHasSoloButton;
178
179 if( bNarrow )
180 {
181 if( solo )
182 GetNarrowSoloHorizontalBounds( rect, dest );
183 else
184 GetNarrowMuteHorizontalBounds( rect, dest );
185 }
186 else
187 GetWideMuteSoloHorizontalBounds( rect, dest );
188
189 if( bSameRow || !solo )
190 dest.y = rect.y + yMute;
191 else
192 dest.y = rect.y + ySolo;
193
194 }
195
196
197 #include <mutex>
StaticTCPLines()198 const TCPLines& PlayableTrackControls::StaticTCPLines()
199 {
200 static TCPLines playableTrackTCPLines;
201 static std::once_flag flag;
202 std::call_once( flag, []{
203 playableTrackTCPLines = CommonTrackControls::StaticTCPLines();
204 playableTrackTCPLines.insert( playableTrackTCPLines.end(), {
205 #ifdef EXPERIMENTAL_DA
206 // DA: Has Mute and Solo on separate lines.
207 { TCPLine::kItemMute, kTrackInfoBtnSize + 1, 1,
208 WideMuteDrawFunction },
209 { TCPLine::kItemSolo, kTrackInfoBtnSize + 1, 0,
210 WideSoloDrawFunction },
211 #else
212 { TCPLine::kItemMute | TCPLine::kItemSolo, kTrackInfoBtnSize + 1, 0,
213 MuteAndSoloDrawFunction },
214 #endif
215
216 } );
217 } );
218 return playableTrackTCPLines;
219 }
220