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 (results.empty()) {
61 if (NULL != (result = TrackSelectHandle::HitAnywhere(
63 results.push_back(result);
64 }
65
66 return results;
67}
68
69enum
70{
76};
77
79 : public PopupMenuTable
80 , private PrefsListener
81{
83 : PopupMenuTable{ "Track" }
84 {}
86
87public:
88 static TrackMenuTable &Instance();
89
90private:
91 void OnSetName(wxCommandEvent &);
92 void OnMoveTrack(wxCommandEvent &event);
93
94 void InitUserData(void *pUserData) override;
95
97
98 void UpdatePrefs() override
99 {
100 // Because labels depend on keyboard preferences
102 }
103};
104
106{
107 static TrackMenuTable instance;
108 return instance;
109}
110
111void TrackMenuTable::InitUserData(void *pUserData)
112{
113 mpData = static_cast<CommonTrackControls::InitMenuData*>(pUserData);
114}
115
117 static const auto enableIfCanMove = [](bool up){ return
118 [up]( PopupMenuHandler &handler, wxMenu &menu, int id ){
119 auto pData = static_cast<TrackMenuTable&>( handler ).mpData;
120 const auto &tracks = TrackList::Get( pData->project );
121 auto &track = pData->track;
122 menu.Enable(id,
123 up ? tracks.CanMoveUp(track) : tracks.CanMoveDown(track));
124 };
125 };
126 //First section in the menu doesn't need BeginSection/EndSection
127 AppendItem( "Name", OnSetNameID, XXO("Re&name Track..."), POPUP_MENU_FN( OnSetName ) );
128
129 BeginSection( "Move" );
131 // It is not correct to use NormalizedKeyString::Display here --
132 // wxWidgets will apply its equivalent to the key names passed to menu
133 // functions.
135 XXO("Move Track &Up").Join(
136 Verbatim(
137 CommandManager::Get( mpData->project ).
138 // using GET to compose menu item name for wxWidgets
139 GetKeyFromName(wxT("TrackMoveUp")).GET() ),
140 wxT("\t")
141 ),
142 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
143 AppendItem( "Down",
145 XXO("Move Track &Down").Join(
146 Verbatim(
147 CommandManager::Get( mpData->project ).
148 // using GET to compose menu item name for wxWidgets
149 GetKeyFromName(wxT("TrackMoveDown")).GET() ),
150 wxT("\t")
151 ),
152 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
155 XXO("Move Track to &Top").Join(
156 Verbatim(
157 CommandManager::Get( mpData->project ).
158 // using GET to compose menu item name for wxWidgets
159 GetKeyFromName(wxT("TrackMoveTop")).GET() ),
160 wxT("\t")
161 ),
162 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
163 AppendItem( "Bottom",
165 XXO("Move Track to &Bottom").Join(
166 Verbatim(
167 CommandManager::Get( mpData->project ).
168 // using GET to compose menu item name for wxWidgets
169 GetKeyFromName(wxT("TrackMoveBottom")).GET() ),
170 wxT("\t")
171 ),
172 POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
175
176
177
178
179// An example of using an AudacityCommand simply to create a dialog.
180// We can add additional functions later, if we want to make it
181// available to scripting.
182// However there is no reason to, as SetTrackStatus is already provided.
184{
185public:
187
188 // ComponentInterface overrides
190 { return Symbol; }
191 //TranslatableString GetDescription() override {return XO("Sets the track name.");};
192 //bool VisitSettings( SettingsVisitor & S ) override;
193 void PopulateOrExchange(ShuttleGui & S) override;
194 //bool Apply(const CommandContext & context) override;
195
196 // Provide an override, if we want the help button.
197 // ManualPageID ManualPage() override {return {};}
198public:
199 wxString mName;
200};
201
203{ XO("Set Track Name") };
204
206{
207 S.AddSpace(0, 5);
208
209 S.StartMultiColumn(2, wxALIGN_CENTER);
210 {
211 S.TieTextBox(XXO("Name:"),mName,60);
212 }
213 S.EndMultiColumn();
214}
215
216void TrackMenuTable::OnSetName(wxCommandEvent &)
217{
218 auto &track = mpData->track;
219 AudacityProject *const proj = &mpData->project;
220 const wxString oldName = track.GetName();
221
223 Command.mName = oldName;
224 // Bug 1837 : We need an OK/Cancel result if we are to enter a blank string.
225 bool bResult = Command.PromptUser( &GetProjectFrame( *proj ) );
226 if (bResult)
227 {
228 wxString newName = Command.mName;
229 track.SetName(newName);
230
231 ProjectHistory::Get( *proj )
232 .PushState(
233 XO("Renamed '%s' to '%s'").Format( oldName, newName ),
234 XO("Name Change"));
235
237 }
238}
239
240void TrackMenuTable::OnMoveTrack(wxCommandEvent &event)
241{
244 switch (event.GetId()) {
245 default:
246 wxASSERT(false);
247 case OnMoveUpID:
248 choice = TrackUtilities::OnMoveUpID; break;
249 case OnMoveDownID:
250 choice = TrackUtilities::OnMoveDownID; break;
251 case OnMoveTopID:
252 choice = TrackUtilities::OnMoveTopID; break;
253 case OnMoveBottomID:
254 choice = TrackUtilities::OnMoveBottomID; break;
255 }
256
258
259 // MoveTrack already refreshed TrackPanel, which means repaint will happen.
260 // This is a harmless redundancy:
262}
263
265 const wxRect &rect, wxWindow *pParent, const wxPoint *,
266 AudacityProject *pProject)
267{
268 using namespace RefreshCode;
269 wxRect buttonRect;
270 CommonTrackInfo::GetTitleBarRect(rect, buttonRect);
271
272 auto track = FindTrack();
273 if (!track)
274 return RefreshNone;
275
276 InitMenuData data{ *pProject, *track, pParent, RefreshNone };
277
278 const auto pTable = &TrackMenuTable::Instance();
279 auto pMenu = PopupMenuTable::BuildMenu(pTable, &data);
280
281 PopupMenuTable *const pExtension = GetMenuExtension(track.get());
282 if (pExtension)
283 PopupMenuTable::ExtendMenu( *pMenu, *pExtension );
284
285 pMenu->Popup( *pParent,
286 { buttonRect.x + 1, buttonRect.y + buttonRect.height + 1 } );
287
288 return data.result;
289}
290
291// Some old cut-and-paste legacy from TrackPanel.cpp here:
292#if 0
293void TrackInfo::DrawBordersWithin
294 ( wxDC* dc, const wxRect & rect, const Track &track ) const
295{
296 AColor::Dark(dc, false); // same color as border of toolbars (ToolBar::OnPaint())
297
298 // below close box and title bar
299 wxRect buttonRect;
300 GetTitleBarRect( rect, buttonRect );
302 (*dc, rect.x, buttonRect.y + buttonRect.height,
303 rect.width - 1, buttonRect.y + buttonRect.height);
304
305 // between close box and title bar
307 (*dc, buttonRect.x, buttonRect.y,
308 buttonRect.x, buttonRect.y + buttonRect.height - 1);
309
310 GetMuteSoloRect( rect, buttonRect, false, true, &track );
311
312 bool bHasMuteSolo = dynamic_cast<const PlayableTrack*>( &track ) != NULL;
313 if( bHasMuteSolo && !TrackInfo::HideTopItem( rect, buttonRect ) )
314 {
315 // above mute/solo
317 (*dc, rect.x, buttonRect.y,
318 rect.width - 1, buttonRect.y);
319
320 // between mute/solo
321 // Draw this little line; if there is no solo, wide mute button will
322 // overpaint it later:
324 (*dc, buttonRect.x + buttonRect.width, buttonRect.y,
325 buttonRect.x + buttonRect.width, buttonRect.y + buttonRect.height - 1);
326
327 // below mute/solo
329 (*dc, rect.x, buttonRect.y + buttonRect.height,
330 rect.width - 1, buttonRect.y + buttonRect.height);
331 }
332
333 // left of and above minimize button
334 wxRect minimizeRect;
335 this->GetMinimizeRect(rect, minimizeRect);
337 (*dc, minimizeRect.x - 1, minimizeRect.y,
338 minimizeRect.x - 1, minimizeRect.y + minimizeRect.height - 1);
340 (*dc, minimizeRect.x, minimizeRect.y - 1,
341 minimizeRect.x + minimizeRect.width - 1, minimizeRect.y - 1);
342}
343#endif
344
347 const wxRect &rect_, unsigned iPass )
348{
349 if ( iPass == TrackArtist::PassMargins ) {
350 // fill in label
351 auto dc = &context.dc;
352 const auto pTrack = FindTrack();
353 AColor::MediumTrackInfo( dc, pTrack && pTrack->GetSelected() );
354 dc->DrawRectangle( rect_ );
355 }
356
357 if ( iPass == TrackArtist::PassControls ) {
358 // Given rectangle excludes left and right margins, and encompasses a
359 // channel group of tracks, plus the resizer area below
360 auto pTrack = FindTrack();
361 // First counteract DrawingArea() correction
362 wxRect rect{ rect_.x, rect_.y, rect_.width - 1, rect_.height };
363
364 // Vaughan, 2010-08-24: No longer doing this.
365 // Draw sync-lock tiles in ruler area.
366 //if (SyncLock::IsSyncLockSelected(t)) {
367 // wxRect tileFill = rect;
368 // tileFill.x = mViewInfo->GetVRulerOffset();
369 // tileFill.width = mViewInfo->GetVRulerWidth();
370 // TrackArt::DrawSyncLockTiles(dc, tileFill);
371 //}
372
373 if (pTrack)
374 // Draw things within the track control panel
375 CommonTrackInfo::DrawItems( context, rect, *pTrack );
376
377 //mTrackInfo.DrawBordersWithin( dc, rect, *t );
378 }
379
380 // Some old cut-and-paste legacy from TrackPanel.cpp here:
381#undef USE_BEVELS
382#ifdef USE_BEVELS
383 // This branch is not now used
384 // PRL: todo: banish magic numbers.
385 // PRL: vrul was the x coordinate of left edge of the vertical ruler.
386 // PRL: bHasMuteSolo was true iff the track was WaveTrack.
387 if( bHasMuteSolo )
388 {
389 int ylast = rect.height-20;
390 int ybutton = wxMin(32,ylast-17);
391 int ybuttonEnd = 67;
392
393 fill=wxRect( rect.x+1, rect.y+17, vrul-6, ybutton);
394 AColor::BevelTrackInfo( *dc, true, fill );
395
396 if( ybuttonEnd < ylast ){
397 fill=wxRect( rect.x+1, rect.y+ybuttonEnd, fill.width, ylast - ybuttonEnd);
398 AColor::BevelTrackInfo( *dc, true, fill );
399 }
400 }
401 else
402 {
403 fill=wxRect( rect.x+1, rect.y+17, vrul-6, rect.height-37);
404 AColor::BevelTrackInfo( *dc, true, fill );
405 }
406#endif
407
408}
409
412 const wxRect &rect, const wxRect &, unsigned iPass )
413{
414 if ( iPass == TrackArtist::PassControls )
415 // Some bevels spill out right
416 return { rect.x, rect.y, rect.width + 1, rect.height };
417 else
418 return rect;
419}
420
422{
424}
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 ...
ResultType Join(const ContainerType< ResultType, Rest... > &container, const SeparatorType &separator)
Definition: StringUtils.h:52
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:185
static void MediumTrackInfo(wxDC *dc, bool selected)
Definition: AColor.cpp:427
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:433
static void BevelTrackInfo(wxDC &dc, bool up, const wxRect &r, bool highlight=false)
Definition: AColor.cpp:338
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< 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 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:110
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
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
AUDACITY_DLL_API void DoMoveTrack(AudacityProject &project, Track &target, MoveChoice choice)
Move a track up, down, to top or to bottom.