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
131 BeginSection( "Basic" );
132 AppendItem( "Name", OnSetNameID, XXO("&Name..."), POPUP_MENU_FN( OnSetName ) );
134 BeginSection( "Move" );
136 // It is not correct to use NormalizedKeyString::Display here --
137 // wxWidgets will apply its equivalent to the key names passed to menu
138 // functions.
140 XXO("Move Track &Up").Join(
141 Verbatim(
142 CommandManager::Get( mpData->project ).
143 // using GET to compose menu item name for wxWidgets
144 GetKeyFromName(wxT("TrackMoveUp")).GET() ),
145 wxT("\t")
146 ),
147 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
148 AppendItem( "Down",
150 XXO("Move Track &Down").Join(
151 Verbatim(
152 CommandManager::Get( mpData->project ).
153 // using GET to compose menu item name for wxWidgets
154 GetKeyFromName(wxT("TrackMoveDown")).GET() ),
155 wxT("\t")
156 ),
157 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
160 XXO("Move Track to &Top").Join(
161 Verbatim(
162 CommandManager::Get( mpData->project ).
163 // using GET to compose menu item name for wxWidgets
164 GetKeyFromName(wxT("TrackMoveTop")).GET() ),
165 wxT("\t")
166 ),
167 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
168 AppendItem( "Bottom",
170 XXO("Move Track to &Bottom").Join(
171 Verbatim(
172 CommandManager::Get( mpData->project ).
173 // using GET to compose menu item name for wxWidgets
174 GetKeyFromName(wxT("TrackMoveBottom")).GET() ),
175 wxT("\t")
176 ),
177 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
178 EndSection();
180
181
182
183
184// An example of using an AudacityCommand simply to create a dialog.
185// We can add additional functions later, if we want to make it
186// available to scripting.
187// However there is no reason to, as SetTrackStatus is already provided.
189{
190public:
192
193 // ComponentInterface overrides
195 { return Symbol; }
196 //TranslatableString GetDescription() override {return XO("Sets the track name.");};
197 //bool VisitSettings( SettingsVisitor & S ) override;
198 void PopulateOrExchange(ShuttleGui & S) override;
199 //bool Apply(const CommandContext & context) override;
200
201 // Provide an override, if we want the help button.
202 // ManualPageID ManualPage() override {return {};}
203public:
204 wxString mName;
205};
206
208{ XO("Set Track Name") };
209
211{
212 S.AddSpace(0, 5);
213
214 S.StartMultiColumn(2, wxALIGN_CENTER);
215 {
216 S.TieTextBox(XXO("Name:"),mName,60);
217 }
218 S.EndMultiColumn();
219}
220
221void TrackMenuTable::OnSetName(wxCommandEvent &)
222{
223 Track *const pTrack = mpData->pTrack;
224 if (pTrack)
225 {
226 AudacityProject *const proj = &mpData->project;
227 const wxString oldName = pTrack->GetName();
228
230 Command.mName = oldName;
231 // Bug 1837 : We need an OK/Cancel result if we are to enter a blank string.
232 bool bResult = Command.PromptUser( &GetProjectFrame( *proj ) );
233 if (bResult)
234 {
235 wxString newName = Command.mName;
236 pTrack->SetName(newName);
237
238 ProjectHistory::Get( *proj )
239 .PushState(
240 XO("Renamed '%s' to '%s'").Format( oldName, newName ),
241 XO("Name Change"));
242
244 }
245 }
246}
247
248void TrackMenuTable::OnMoveTrack(wxCommandEvent &event)
249{
252 switch (event.GetId()) {
253 default:
254 wxASSERT(false);
255 case OnMoveUpID:
256 choice = TrackUtilities::OnMoveUpID; break;
257 case OnMoveDownID:
258 choice = TrackUtilities::OnMoveDownID; break;
259 case OnMoveTopID:
260 choice = TrackUtilities::OnMoveTopID; break;
261 case OnMoveBottomID:
262 choice = TrackUtilities::OnMoveBottomID; break;
263 }
264
266
267 // MoveTrack already refreshed TrackPanel, which means repaint will happen.
268 // This is a harmless redundancy:
270}
271
273 const wxRect &rect, wxWindow *pParent, const wxPoint *,
274 AudacityProject *pProject)
275{
276 using namespace RefreshCode;
277 wxRect buttonRect;
278 CommonTrackInfo::GetTitleBarRect(rect, buttonRect);
279
280 auto track = FindTrack();
281 if (!track)
282 return RefreshNone;
283
284 InitMenuData data{ *pProject, track.get(), pParent, RefreshNone };
285
286 const auto pTable = &TrackMenuTable::Instance();
287 auto pMenu = PopupMenuTable::BuildMenu(pTable, &data);
288
289 PopupMenuTable *const pExtension = GetMenuExtension(track.get());
290 if (pExtension)
291 PopupMenuTable::ExtendMenu( *pMenu, *pExtension );
292
293 pMenu->Popup( *pParent,
294 { buttonRect.x + 1, buttonRect.y + buttonRect.height + 1 } );
295
296 return data.result;
297}
298
299// Some old cut-and-paste legacy from TrackPanel.cpp here:
300#if 0
301void TrackInfo::DrawBordersWithin
302 ( wxDC* dc, const wxRect & rect, const Track &track ) const
303{
304 AColor::Dark(dc, false); // same color as border of toolbars (ToolBar::OnPaint())
305
306 // below close box and title bar
307 wxRect buttonRect;
308 GetTitleBarRect( rect, buttonRect );
310 (*dc, rect.x, buttonRect.y + buttonRect.height,
311 rect.width - 1, buttonRect.y + buttonRect.height);
312
313 // between close box and title bar
315 (*dc, buttonRect.x, buttonRect.y,
316 buttonRect.x, buttonRect.y + buttonRect.height - 1);
317
318 GetMuteSoloRect( rect, buttonRect, false, true, &track );
319
320 bool bHasMuteSolo = dynamic_cast<const PlayableTrack*>( &track ) != NULL;
321 if( bHasMuteSolo && !TrackInfo::HideTopItem( rect, buttonRect ) )
322 {
323 // above mute/solo
325 (*dc, rect.x, buttonRect.y,
326 rect.width - 1, buttonRect.y);
327
328 // between mute/solo
329 // Draw this little line; if there is no solo, wide mute button will
330 // overpaint it later:
332 (*dc, buttonRect.x + buttonRect.width, buttonRect.y,
333 buttonRect.x + buttonRect.width, buttonRect.y + buttonRect.height - 1);
334
335 // below mute/solo
337 (*dc, rect.x, buttonRect.y + buttonRect.height,
338 rect.width - 1, buttonRect.y + buttonRect.height);
339 }
340
341 // left of and above minimize button
342 wxRect minimizeRect;
343 this->GetMinimizeRect(rect, minimizeRect);
345 (*dc, minimizeRect.x - 1, minimizeRect.y,
346 minimizeRect.x - 1, minimizeRect.y + minimizeRect.height - 1);
348 (*dc, minimizeRect.x, minimizeRect.y - 1,
349 minimizeRect.x + minimizeRect.width - 1, minimizeRect.y - 1);
350}
351#endif
352
355 const wxRect &rect_, unsigned iPass )
356{
357 if ( iPass == TrackArtist::PassMargins ) {
358 // fill in label
359 auto dc = &context.dc;
360 const auto pTrack = FindTrack();
361 AColor::MediumTrackInfo( dc, pTrack && pTrack->GetSelected() );
362 dc->DrawRectangle( rect_ );
363 }
364
365 if ( iPass == TrackArtist::PassControls ) {
366 // Given rectangle excludes left and right margins, and encompasses a
367 // channel group of tracks, plus the resizer area below
368 auto pTrack = FindTrack();
369 // First counteract DrawingArea() correction
370 wxRect rect{ rect_.x, rect_.y, rect_.width - 1, rect_.height };
371
372 // Vaughan, 2010-08-24: No longer doing this.
373 // Draw sync-lock tiles in ruler area.
374 //if (SyncLock::IsSyncLockSelected(t)) {
375 // wxRect tileFill = rect;
376 // tileFill.x = mViewInfo->GetVRulerOffset();
377 // tileFill.width = mViewInfo->GetVRulerWidth();
378 // TrackArt::DrawSyncLockTiles(dc, tileFill);
379 //}
380
381 if (pTrack)
382 // Draw things within the track control panel
383 CommonTrackInfo::DrawItems( context, rect, *pTrack );
384
385 //mTrackInfo.DrawBordersWithin( dc, rect, *t );
386 }
387
388 // Some old cut-and-paste legacy from TrackPanel.cpp here:
389#undef USE_BEVELS
390#ifdef USE_BEVELS
391 // This branch is not now used
392 // PRL: todo: banish magic numbers.
393 // PRL: vrul was the x coordinate of left edge of the vertical ruler.
394 // PRL: bHasMuteSolo was true iff the track was WaveTrack.
395 if( bHasMuteSolo )
396 {
397 int ylast = rect.height-20;
398 int ybutton = wxMin(32,ylast-17);
399 int ybuttonEnd = 67;
400
401 fill=wxRect( rect.x+1, rect.y+17, vrul-6, ybutton);
402 AColor::BevelTrackInfo( *dc, true, fill );
403
404 if( ybuttonEnd < ylast ){
405 fill=wxRect( rect.x+1, rect.y+ybuttonEnd, fill.width, ylast - ybuttonEnd);
406 AColor::BevelTrackInfo( *dc, true, fill );
407 }
408 }
409 else
410 {
411 fill=wxRect( rect.x+1, rect.y+17, vrul-6, rect.height-37);
412 AColor::BevelTrackInfo( *dc, true, fill );
413 }
414#endif
415
416}
417
420 const wxRect &rect, const wxRect &, unsigned iPass )
421{
422 if ( iPass == TrackArtist::PassControls )
423 // Some bevels spill out right
424 return { rect.x, rect.y, rect.width + 1, rect.height };
425 else
426 return rect;
427}
428
430{
432}
wxT("CloseDown"))
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
EndSection()
AppendItem("Name", OnSetNameID, XXO("&Name..."), POPUP_MENU_FN(OnSetName))
BeginSection("Basic")
@ OnMoveBottomID
@ OnSetNameID
@ OnMoveDownID
@ OnMoveTopID
@ OnMoveUpID
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:561
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:630
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.