Audacity 3.2.0
CommonTrackControls.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5CommonTrackControls.cpp
6
7Paul Licameli split from TrackControls.cpp
8
9**********************************************************************/
10
11#include "CommonTrackControls.h"
12
13#include "TrackButtonHandles.h"
14#include "TrackSelectHandle.h"
15#include "AColor.h"
16#include "../../RefreshCode.h"
17#include "Project.h"
18#include "ProjectHistory.h"
19#include "../../ProjectWindows.h"
20#include "../../TrackArtist.h"
21#include "CommonTrackInfo.h"
22#include "../../TrackPanelDrawingContext.h"
23#include "../../TrackPanelMouseEvent.h"
24#include "../../TrackUtilities.h"
25#include <wx/textdlg.h>
26#include "../../commands/AudacityCommand.h"
27#include "CommandManager.h"
28#include "ShuttleGui.h"
29#include "Track.h"
30#include "../../widgets/PopupMenuTable.h"
31
32#include <wx/dc.h>
33#include <wx/frame.h>
34
35std::vector<UIHandlePtr> CommonTrackControls::HitTest
36(const TrackPanelMouseState &st,
37 const AudacityProject *WXUNUSED(project))
38{
39 // Hits are mutually exclusive, results single
40
41 const wxMouseState &state = st.state;
42 const wxRect &rect = st.rect;
43 UIHandlePtr result;
44 std::vector<UIHandlePtr> results;
45
46 auto sThis = shared_from_this();
47
48 if (NULL != (result = CloseButtonHandle::HitTest(
49 mCloseHandle, state, rect, this)))
50 results.push_back(result);
51
52 if (NULL != (result = MenuButtonHandle::HitTest(
53 mMenuHandle, state, rect, sThis)))
54 results.push_back(result);
55
56 if (NULL != (result = MinimizeButtonHandle::HitTest(
57 mMinimizeHandle, state, rect, this)))
58 results.push_back(result);
59
60 if (NULL != (result = SelectButtonHandle::HitTest(
61 mSelectButtonHandle, state, rect, this)))
62 results.push_back(result);
63
64 if (results.empty()) {
65 if (NULL != (result = TrackSelectHandle::HitAnywhere(
67 results.push_back(result);
68 }
69
70 return results;
71}
72
73enum
74{
80};
81
83 : public PopupMenuTable
84 , private PrefsListener
85{
87 : PopupMenuTable{ "Track" }
88 {}
90
91public:
92 static TrackMenuTable &Instance();
93
94private:
95 void OnSetName(wxCommandEvent &);
96 void OnMoveTrack(wxCommandEvent &event);
97
98 void InitUserData(void *pUserData) override;
99
101
102 void UpdatePrefs() override
103 {
104 // Because labels depend on keyboard preferences
106 }
107};
108
110{
111 static TrackMenuTable instance;
112 return instance;
113}
114
115void TrackMenuTable::InitUserData(void *pUserData)
116{
117 mpData = static_cast<CommonTrackControls::InitMenuData*>(pUserData);
118}
119
121 static const auto enableIfCanMove = [](bool up){ return
122 [up]( PopupMenuHandler &handler, wxMenu &menu, int id ){
123 auto pData = static_cast<TrackMenuTable&>( handler ).mpData;
124 const auto &tracks = TrackList::Get( pData->project );
125 Track *const pTrack = pData->pTrack;
126 menu.Enable( id,
127 up ? tracks.CanMoveUp(pTrack) : tracks.CanMoveDown(pTrack) );
128 };
129 };
130 //First section in the menu doesn't need BeginSection/EndSection
131 AppendItem( "Name", OnSetNameID, XXO("Re&name Track..."), POPUP_MENU_FN( OnSetName ) );
132
133 BeginSection( "Move" );
135 // It is not correct to use NormalizedKeyString::Display here --
136 // wxWidgets will apply its equivalent to the key names passed to menu
137 // functions.
139 XXO("Move Track &Up").Join(
140 Verbatim(
141 CommandManager::Get( mpData->project ).
142 // using GET to compose menu item name for wxWidgets
143 GetKeyFromName(wxT("TrackMoveUp")).GET() ),
144 wxT("\t")
145 ),
146 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
147 AppendItem( "Down",
149 XXO("Move Track &Down").Join(
150 Verbatim(
151 CommandManager::Get( mpData->project ).
152 // using GET to compose menu item name for wxWidgets
153 GetKeyFromName(wxT("TrackMoveDown")).GET() ),
154 wxT("\t")
155 ),
156 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
159 XXO("Move Track to &Top").Join(
160 Verbatim(
161 CommandManager::Get( mpData->project ).
162 // using GET to compose menu item name for wxWidgets
163 GetKeyFromName(wxT("TrackMoveTop")).GET() ),
164 wxT("\t")
165 ),
166 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
167 AppendItem( "Bottom",
169 XXO("Move Track to &Bottom").Join(
170 Verbatim(
171 CommandManager::Get( mpData->project ).
172 // using GET to compose menu item name for wxWidgets
173 GetKeyFromName(wxT("TrackMoveBottom")).GET() ),
174 wxT("\t")
175 ),
176 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
179
180
181
182
183// An example of using an AudacityCommand simply to create a dialog.
184// We can add additional functions later, if we want to make it
185// available to scripting.
186// However there is no reason to, as SetTrackStatus is already provided.
188{
189public:
191
192 // ComponentInterface overrides
194 { return Symbol; }
195 //TranslatableString GetDescription() override {return XO("Sets the track name.");};
196 //bool VisitSettings( SettingsVisitor & S ) override;
197 void PopulateOrExchange(ShuttleGui & S) override;
198 //bool Apply(const CommandContext & context) override;
199
200 // Provide an override, if we want the help button.
201 // ManualPageID ManualPage() override {return {};}
202public:
203 wxString mName;
204};
205
207{ XO("Set Track Name") };
208
210{
211 S.AddSpace(0, 5);
212
213 S.StartMultiColumn(2, wxALIGN_CENTER);
214 {
215 S.TieTextBox(XXO("Name:"),mName,60);
216 }
217 S.EndMultiColumn();
218}
219
220void TrackMenuTable::OnSetName(wxCommandEvent &)
221{
222 Track *const pTrack = mpData->pTrack;
223 if (pTrack)
224 {
225 AudacityProject *const proj = &mpData->project;
226 const wxString oldName = pTrack->GetName();
227
229 Command.mName = oldName;
230 // Bug 1837 : We need an OK/Cancel result if we are to enter a blank string.
231 bool bResult = Command.PromptUser( &GetProjectFrame( *proj ) );
232 if (bResult)
233 {
234 wxString newName = Command.mName;
235 pTrack->SetName(newName);
236
237 ProjectHistory::Get( *proj )
238 .PushState(
239 XO("Renamed '%s' to '%s'").Format( oldName, newName ),
240 XO("Name Change"));
241
243 }
244 }
245}
246
247void TrackMenuTable::OnMoveTrack(wxCommandEvent &event)
248{
251 switch (event.GetId()) {
252 default:
253 wxASSERT(false);
254 case OnMoveUpID:
255 choice = TrackUtilities::OnMoveUpID; break;
256 case OnMoveDownID:
257 choice = TrackUtilities::OnMoveDownID; break;
258 case OnMoveTopID:
259 choice = TrackUtilities::OnMoveTopID; break;
260 case OnMoveBottomID:
261 choice = TrackUtilities::OnMoveBottomID; break;
262 }
263
265
266 // MoveTrack already refreshed TrackPanel, which means repaint will happen.
267 // This is a harmless redundancy:
269}
270
272 const wxRect &rect, wxWindow *pParent, const wxPoint *,
273 AudacityProject *pProject)
274{
275 using namespace RefreshCode;
276 wxRect buttonRect;
277 CommonTrackInfo::GetTitleBarRect(rect, buttonRect);
278
279 auto track = FindTrack();
280 if (!track)
281 return RefreshNone;
282
283 InitMenuData data{ *pProject, track.get(), pParent, RefreshNone };
284
285 const auto pTable = &TrackMenuTable::Instance();
286 auto pMenu = PopupMenuTable::BuildMenu(pTable, &data);
287
288 PopupMenuTable *const pExtension = GetMenuExtension(track.get());
289 if (pExtension)
290 PopupMenuTable::ExtendMenu( *pMenu, *pExtension );
291
292 pMenu->Popup( *pParent,
293 { buttonRect.x + 1, buttonRect.y + buttonRect.height + 1 } );
294
295 return data.result;
296}
297
298// Some old cut-and-paste legacy from TrackPanel.cpp here:
299#if 0
300void TrackInfo::DrawBordersWithin
301 ( wxDC* dc, const wxRect & rect, const Track &track ) const
302{
303 AColor::Dark(dc, false); // same color as border of toolbars (ToolBar::OnPaint())
304
305 // below close box and title bar
306 wxRect buttonRect;
307 GetTitleBarRect( rect, buttonRect );
309 (*dc, rect.x, buttonRect.y + buttonRect.height,
310 rect.width - 1, buttonRect.y + buttonRect.height);
311
312 // between close box and title bar
314 (*dc, buttonRect.x, buttonRect.y,
315 buttonRect.x, buttonRect.y + buttonRect.height - 1);
316
317 GetMuteSoloRect( rect, buttonRect, false, true, &track );
318
319 bool bHasMuteSolo = dynamic_cast<const PlayableTrack*>( &track ) != NULL;
320 if( bHasMuteSolo && !TrackInfo::HideTopItem( rect, buttonRect ) )
321 {
322 // above mute/solo
324 (*dc, rect.x, buttonRect.y,
325 rect.width - 1, buttonRect.y);
326
327 // between mute/solo
328 // Draw this little line; if there is no solo, wide mute button will
329 // overpaint it later:
331 (*dc, buttonRect.x + buttonRect.width, buttonRect.y,
332 buttonRect.x + buttonRect.width, buttonRect.y + buttonRect.height - 1);
333
334 // below mute/solo
336 (*dc, rect.x, buttonRect.y + buttonRect.height,
337 rect.width - 1, buttonRect.y + buttonRect.height);
338 }
339
340 // left of and above minimize button
341 wxRect minimizeRect;
342 this->GetMinimizeRect(rect, minimizeRect);
344 (*dc, minimizeRect.x - 1, minimizeRect.y,
345 minimizeRect.x - 1, minimizeRect.y + minimizeRect.height - 1);
347 (*dc, minimizeRect.x, minimizeRect.y - 1,
348 minimizeRect.x + minimizeRect.width - 1, minimizeRect.y - 1);
349}
350#endif
351
354 const wxRect &rect_, unsigned iPass )
355{
356 if ( iPass == TrackArtist::PassMargins ) {
357 // fill in label
358 auto dc = &context.dc;
359 const auto pTrack = FindTrack();
360 AColor::MediumTrackInfo( dc, pTrack && pTrack->GetSelected() );
361 dc->DrawRectangle( rect_ );
362 }
363
364 if ( iPass == TrackArtist::PassControls ) {
365 // Given rectangle excludes left and right margins, and encompasses a
366 // channel group of tracks, plus the resizer area below
367 auto pTrack = FindTrack();
368 // First counteract DrawingArea() correction
369 wxRect rect{ rect_.x, rect_.y, rect_.width - 1, rect_.height };
370
371 // Vaughan, 2010-08-24: No longer doing this.
372 // Draw sync-lock tiles in ruler area.
373 //if (SyncLock::IsSyncLockSelected(t)) {
374 // wxRect tileFill = rect;
375 // tileFill.x = mViewInfo->GetVRulerOffset();
376 // tileFill.width = mViewInfo->GetVRulerWidth();
377 // TrackArt::DrawSyncLockTiles(dc, tileFill);
378 //}
379
380 if (pTrack)
381 // Draw things within the track control panel
382 CommonTrackInfo::DrawItems( context, rect, *pTrack );
383
384 //mTrackInfo.DrawBordersWithin( dc, rect, *t );
385 }
386
387 // Some old cut-and-paste legacy from TrackPanel.cpp here:
388#undef USE_BEVELS
389#ifdef USE_BEVELS
390 // This branch is not now used
391 // PRL: todo: banish magic numbers.
392 // PRL: vrul was the x coordinate of left edge of the vertical ruler.
393 // PRL: bHasMuteSolo was true iff the track was WaveTrack.
394 if( bHasMuteSolo )
395 {
396 int ylast = rect.height-20;
397 int ybutton = wxMin(32,ylast-17);
398 int ybuttonEnd = 67;
399
400 fill=wxRect( rect.x+1, rect.y+17, vrul-6, ybutton);
401 AColor::BevelTrackInfo( *dc, true, fill );
402
403 if( ybuttonEnd < ylast ){
404 fill=wxRect( rect.x+1, rect.y+ybuttonEnd, fill.width, ylast - ybuttonEnd);
405 AColor::BevelTrackInfo( *dc, true, fill );
406 }
407 }
408 else
409 {
410 fill=wxRect( rect.x+1, rect.y+17, vrul-6, rect.height-37);
411 AColor::BevelTrackInfo( *dc, true, fill );
412 }
413#endif
414
415}
416
419 const wxRect &rect, const wxRect &, unsigned iPass )
420{
421 if ( iPass == TrackArtist::PassControls )
422 // Some bevels spill out right
423 return { rect.x, rect.y, rect.width + 1, rect.height };
424 else
425 return rect;
426}
427
429{
431}
wxT("CloseDown"))
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
EndSection()
@ OnMoveBottomID
@ OnSetNameID
@ OnMoveDownID
@ OnMoveTopID
@ OnMoveUpID
AppendItem("Name", OnSetNameID, XXO("Re&name Track..."), POPUP_MENU_FN(OnSetName))
BeginSection("Move")
static const auto enableIfCanMove
std::vector< TrackInfo::TCPLine > TCPLines
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define END_POPUP_MENU()
#define BEGIN_POPUP_MENU(HandlerClass)
#define POPUP_MENU_FN(memFn)
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
const auto tracks
const auto project
#define S(N)
Definition: ToChars.cpp:64
declares abstract base class Track, TrackList, and iterators over TrackList
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
int id
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static void MediumTrackInfo(wxDC *dc, bool selected)
Definition: AColor.cpp:433
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:443
static void BevelTrackInfo(wxDC &dc, bool up, const wxRect &r, bool highlight=false)
Definition: AColor.cpp:340
Base class for command in Audacity.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static UIHandlePtr HitTest(std::weak_ptr< CloseButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell)
static CommandManager & Get(AudacityProject &project)
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
std::weak_ptr< SelectButtonHandle > mSelectButtonHandle
std::weak_ptr< TrackSelectHandle > mSelectHandle
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
std::weak_ptr< MenuButtonHandle > mMenuHandle
const TCPLines & GetTCPLines() const override
virtual std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *) override=0
unsigned DoContextMenu(const wxRect &rect, wxWindow *pParent, const wxPoint *pPosition, AudacityProject *pProject) override
std::weak_ptr< CloseButtonHandle > mCloseHandle
std::weak_ptr< MinimizeButtonHandle > mMinimizeHandle
virtual PopupMenuTable * GetMenuExtension(Track *pTrack)=0
std::shared_ptr< Track > FindTrack()
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Abstract base class used in importing a file.
static UIHandlePtr HitTest(std::weak_ptr< MenuButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< TrackPanelCell > &pCell)
static UIHandlePtr HitTest(std::weak_ptr< MinimizeButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell)
AudioTrack subclass that can also be audibly replayed by the program.
Definition: PlayableTrack.h:40
static void ExtendMenu(PopupMenu &menu, PopupMenuTable &otherTable)
static std::unique_ptr< PopupMenu > BuildMenu(PopupMenuTable *pTable, void *pUserData=NULL)
A listener notified of changes in preferences.
Definition: Prefs.h:652
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static UIHandlePtr HitTest(std::weak_ptr< SelectButtonHandle > &holder, const wxMouseState &state, const wxRect &rect, TrackPanelCell *pCell)
static const ComponentInterfaceSymbol Symbol
ComponentInterfaceSymbol GetSymbol() const override
void PopulateOrExchange(ShuttleGui &S) override
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:122
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:56
void SetName(const wxString &n)
Definition: Track.cpp:61
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
void OnMoveTrack(wxCommandEvent &event)
void InitUserData(void *pUserData) override
Called before the menu items are appended.
void OnSetName(wxCommandEvent &)
static TrackMenuTable & Instance()
DECLARE_POPUP_MENU(TrackMenuTable)
CommonTrackControls::InitMenuData * mpData
void UpdatePrefs() override
static UIHandlePtr HitAnywhere(std::weak_ptr< TrackSelectHandle > &holder, const std::shared_ptr< Track > &pTrack)
AUDACITY_DLL_API void DrawItems(TrackPanelDrawingContext &context, const wxRect &rect, const Track &track)
AUDACITY_DLL_API void GetMinimizeRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API void GetTitleBarRect(const wxRect &rect, wxRect &dest)
AUDACITY_DLL_API const TCPLines & StaticTCPLines()
AUDACITY_DLL_API bool HideTopItem(const wxRect &rect, const wxRect &subRect, int allowance=0)
constexpr auto Command
Definition: MenuRegistry.h:456
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
void DoMoveTrack(AudacityProject &project, Track *target, MoveChoice choice)
Move a track up, down, to top or to bottom.