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