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 auto &track = pData->track;
126 menu.Enable(id,
127 up ? tracks.CanMoveUp(track) : tracks.CanMoveDown(track));
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 auto &track = mpData->track;
223 AudacityProject *const proj = &mpData->project;
224 const wxString oldName = track.GetName();
225
227 Command.mName = oldName;
228 // Bug 1837 : We need an OK/Cancel result if we are to enter a blank string.
229 bool bResult = Command.PromptUser( &GetProjectFrame( *proj ) );
230 if (bResult)
231 {
232 wxString newName = Command.mName;
233 track.SetName(newName);
234
235 ProjectHistory::Get( *proj )
236 .PushState(
237 XO("Renamed '%s' to '%s'").Format( oldName, newName ),
238 XO("Name Change"));
239
241 }
242}
243
244void TrackMenuTable::OnMoveTrack(wxCommandEvent &event)
245{
248 switch (event.GetId()) {
249 default:
250 wxASSERT(false);
251 case OnMoveUpID:
252 choice = TrackUtilities::OnMoveUpID; break;
253 case OnMoveDownID:
254 choice = TrackUtilities::OnMoveDownID; break;
255 case OnMoveTopID:
256 choice = TrackUtilities::OnMoveTopID; break;
257 case OnMoveBottomID:
258 choice = TrackUtilities::OnMoveBottomID; break;
259 }
260
262
263 // MoveTrack already refreshed TrackPanel, which means repaint will happen.
264 // This is a harmless redundancy:
266}
267
269 const wxRect &rect, wxWindow *pParent, const wxPoint *,
270 AudacityProject *pProject)
271{
272 using namespace RefreshCode;
273 wxRect buttonRect;
274 CommonTrackInfo::GetTitleBarRect(rect, buttonRect);
275
276 auto track = FindTrack();
277 if (!track)
278 return RefreshNone;
279
280 InitMenuData data{ *pProject, *track, pParent, RefreshNone };
281
282 const auto pTable = &TrackMenuTable::Instance();
283 auto pMenu = PopupMenuTable::BuildMenu(pTable, &data);
284
285 PopupMenuTable *const pExtension = GetMenuExtension(track.get());
286 if (pExtension)
287 PopupMenuTable::ExtendMenu( *pMenu, *pExtension );
288
289 pMenu->Popup( *pParent,
290 { buttonRect.x + 1, buttonRect.y + buttonRect.height + 1 } );
291
292 return data.result;
293}
294
295// Some old cut-and-paste legacy from TrackPanel.cpp here:
296#if 0
297void TrackInfo::DrawBordersWithin
298 ( wxDC* dc, const wxRect & rect, const Track &track ) const
299{
300 AColor::Dark(dc, false); // same color as border of toolbars (ToolBar::OnPaint())
301
302 // below close box and title bar
303 wxRect buttonRect;
304 GetTitleBarRect( rect, buttonRect );
306 (*dc, rect.x, buttonRect.y + buttonRect.height,
307 rect.width - 1, buttonRect.y + buttonRect.height);
308
309 // between close box and title bar
311 (*dc, buttonRect.x, buttonRect.y,
312 buttonRect.x, buttonRect.y + buttonRect.height - 1);
313
314 GetMuteSoloRect( rect, buttonRect, false, true, &track );
315
316 bool bHasMuteSolo = dynamic_cast<const PlayableTrack*>( &track ) != NULL;
317 if( bHasMuteSolo && !TrackInfo::HideTopItem( rect, buttonRect ) )
318 {
319 // above mute/solo
321 (*dc, rect.x, buttonRect.y,
322 rect.width - 1, buttonRect.y);
323
324 // between mute/solo
325 // Draw this little line; if there is no solo, wide mute button will
326 // overpaint it later:
328 (*dc, buttonRect.x + buttonRect.width, buttonRect.y,
329 buttonRect.x + buttonRect.width, buttonRect.y + buttonRect.height - 1);
330
331 // below mute/solo
333 (*dc, rect.x, buttonRect.y + buttonRect.height,
334 rect.width - 1, buttonRect.y + buttonRect.height);
335 }
336
337 // left of and above minimize button
338 wxRect minimizeRect;
339 this->GetMinimizeRect(rect, minimizeRect);
341 (*dc, minimizeRect.x - 1, minimizeRect.y,
342 minimizeRect.x - 1, minimizeRect.y + minimizeRect.height - 1);
344 (*dc, minimizeRect.x, minimizeRect.y - 1,
345 minimizeRect.x + minimizeRect.width - 1, minimizeRect.y - 1);
346}
347#endif
348
351 const wxRect &rect_, unsigned iPass )
352{
353 if ( iPass == TrackArtist::PassMargins ) {
354 // fill in label
355 auto dc = &context.dc;
356 const auto pTrack = FindTrack();
357 AColor::MediumTrackInfo( dc, pTrack && pTrack->GetSelected() );
358 dc->DrawRectangle( rect_ );
359 }
360
361 if ( iPass == TrackArtist::PassControls ) {
362 // Given rectangle excludes left and right margins, and encompasses a
363 // channel group of tracks, plus the resizer area below
364 auto pTrack = FindTrack();
365 // First counteract DrawingArea() correction
366 wxRect rect{ rect_.x, rect_.y, rect_.width - 1, rect_.height };
367
368 // Vaughan, 2010-08-24: No longer doing this.
369 // Draw sync-lock tiles in ruler area.
370 //if (SyncLock::IsSyncLockSelected(t)) {
371 // wxRect tileFill = rect;
372 // tileFill.x = mViewInfo->GetVRulerOffset();
373 // tileFill.width = mViewInfo->GetVRulerWidth();
374 // TrackArt::DrawSyncLockTiles(dc, tileFill);
375 //}
376
377 if (pTrack)
378 // Draw things within the track control panel
379 CommonTrackInfo::DrawItems( context, rect, *pTrack );
380
381 //mTrackInfo.DrawBordersWithin( dc, rect, *t );
382 }
383
384 // Some old cut-and-paste legacy from TrackPanel.cpp here:
385#undef USE_BEVELS
386#ifdef USE_BEVELS
387 // This branch is not now used
388 // PRL: todo: banish magic numbers.
389 // PRL: vrul was the x coordinate of left edge of the vertical ruler.
390 // PRL: bHasMuteSolo was true iff the track was WaveTrack.
391 if( bHasMuteSolo )
392 {
393 int ylast = rect.height-20;
394 int ybutton = wxMin(32,ylast-17);
395 int ybuttonEnd = 67;
396
397 fill=wxRect( rect.x+1, rect.y+17, vrul-6, ybutton);
398 AColor::BevelTrackInfo( *dc, true, fill );
399
400 if( ybuttonEnd < ylast ){
401 fill=wxRect( rect.x+1, rect.y+ybuttonEnd, fill.width, ylast - ybuttonEnd);
402 AColor::BevelTrackInfo( *dc, true, fill );
403 }
404 }
405 else
406 {
407 fill=wxRect( rect.x+1, rect.y+17, vrul-6, rect.height-37);
408 AColor::BevelTrackInfo( *dc, true, fill );
409 }
410#endif
411
412}
413
416 const wxRect &rect, const wxRect &, unsigned iPass )
417{
418 if ( iPass == TrackArtist::PassControls )
419 // Some bevels spill out right
420 return { rect.x, rect.y, rect.width + 1, rect.height };
421 else
422 return rect;
423}
424
426{
428}
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:187
static void MediumTrackInfo(wxDC *dc, bool selected)
Definition: AColor.cpp:429
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:435
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: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.