Audacity 3.2.0
BatchProcessDialog.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ApplyMacroDialog.cpp
6
7 Dominic Mazzoni
8 James Crook
9
10*******************************************************************//*******************************************************************/
16#include "BatchProcessDialog.h"
17
18#include <wx/setup.h> // for wxUSE_* macros
19
20#ifdef __WXMSW__
21 #include <wx/ownerdrw.h>
22#endif
23
24#include <wx/defs.h>
25#include <wx/checkbox.h>
26#include <wx/choice.h>
27#include <wx/frame.h>
28#include <wx/log.h>
29#include <wx/statbox.h>
30#include <wx/stattext.h>
31#include <wx/textctrl.h>
32#include <wx/listctrl.h>
33#include <wx/button.h>
34#include <wx/imaglist.h>
35#include <wx/settings.h>
36
37#include "Clipboard.h"
38#include "ShuttleGui.h"
39#include "MenuCreator.h"
40#include "Prefs.h"
41#include "Project.h"
42#include "ProjectFileManager.h"
43#include "ProjectHistory.h"
44#include "ProjectManager.h"
45#include "ProjectWindows.h"
46#include "SelectUtilities.h"
47#include "Track.h"
48#include "CommandManager.h"
49#include "Effect.h"
51#include "effects/EffectUI.h"
52#include "../images/Arrow.xpm"
53#include "../images/Empty9x16.xpm"
54#include "UndoManager.h"
55#include "Viewport.h"
56
57#include "AllThemeResources.h"
58
60#include "FileNames.h"
61#include "Import.h"
62#include "AudacityMessageBox.h"
64#include "HelpSystem.h"
65
66#if wxUSE_ACCESSIBILITY
67#include "WindowAccessible.h"
68#endif
69
70#define MacrosPaletteTitle XO("Macros Palette")
71#define ManageMacrosTitle XO("Manage Macros")
72
73
74// Separate numerical range from the additional buttons
75// in the expanded view (which start at 10,000).
76#define MacrosListID 7001
77#define CommandsListID 7002
78#define ApplyToProjectID 7003
79#define ApplyToFilesID 7004
80#define ExpandID 7005
81#define ShrinkID 7006
82
83BEGIN_EVENT_TABLE(ApplyMacroDialog, wxDialogWrapper)
90
92 wxWindow * parent, AudacityProject &project, bool bInherited):
93 wxDialogWrapper(parent, wxID_ANY, MacrosPaletteTitle,
94 wxDefaultPosition, wxDefaultSize,
95 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
96 , mMacroCommands{ project }
97 , mProject{ project }
98 , mCatalog( &project )
99{
100 mAbort = false;
101 mbExpanded = false;
102 if( bInherited )
103 return;
104 SetLabel(MacrosPaletteTitle); // Provide visual label
105 SetName(MacrosPaletteTitle); // Provide audible label
106 Populate();
107
108}
109
111{
112}
113
115{
116 //------------------------- Main section --------------------
117 ShuttleGui S(this, eIsCreating);
119 // ----------------------- End of main section --------------
120 // Get and validate the currently active macro
121 mActiveMacro = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxT(""));
122 // Go populate the macros list.
124
125 Layout();
126 Fit();
127 wxSize sz = GetSize();
128 SetSizeHints( sz );
129
130 // Size and place window
131 SetSize(std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_X) * 3 / 4, sz.GetWidth()),
132 std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) * 4 / 5, 400));
133
134 Center();
135
136 // Set the column size for the macros list.
137 sz = mMacros->GetClientSize();
138 mMacros->SetColumnWidth(0, sz.x);
139}
140
143{
144 /*i18n-hint: A macro is a sequence of commands that can be applied
145 * to one or more audio files.*/
146 S.StartStatic(XO("Select Macro"), 1);
147 {
148 mMacros = S.Id(MacrosListID).Prop(1)
149 .Style( wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
150 wxLC_SINGLE_SEL)
151 // i18n-hint: This is the heading for a column in the edit macros dialog
152 .AddListControlReportMode( { XO("Macro") } );
153 }
154 S.EndStatic();
155
156 S.StartHorizontalLay(wxEXPAND, 0);
157 {
158 S.AddPrompt( XXO("Apply Macro to:") );
159 wxButton* btn = S.Id(ApplyToProjectID)
160 .Name(XO("Apply macro to project"))
161 .AddButton(XXO("&Project"));
162#if wxUSE_ACCESSIBILITY
163 // so that name can be set on a standard control
164 btn->SetAccessible(safenew WindowAccessible(btn));
165#endif
166
167 btn = S.Id(ApplyToFilesID)
168 .Name(XO("Apply macro to files..."))
169 .AddButton(XXO("&Files..."));
170#if wxUSE_ACCESSIBILITY
171 // so that name can be set on a standard control
172 btn->SetAccessible(safenew WindowAccessible(btn));
173#endif
174 }
175 S.EndHorizontalLay();
176
177 S.StartHorizontalLay(wxEXPAND, 0);
178 {
179 /* i18n-hint: The Expand button makes the dialog bigger, with more in it */
180 mResize = S.Id(ExpandID).AddButton(XXO("&Expand"));
181 S.AddSpace( 10,10,1 );
182 S.AddStandardButtons( eCloseButton | eHelpButton);
183 }
184 S.EndHorizontalLay();
185}
186
191{
193 int i;
194
195 int topItem = mMacros->GetTopItem();
196 mMacros->DeleteAllItems();
197 for (i = 0; i < (int)names.size(); i++) {
198 mMacros->InsertItem(i, names[i]);
199 }
200
201 int item = mMacros->FindItem(-1, mActiveMacro);
202 bool bFound = item >=0;
203 if (item == -1) {
204 item = 0;
205 mActiveMacro = mMacros->GetItemText(0);
206 }
207
208 // Select the name in the list...this will fire an event.
209 mMacros->SetItemState(item, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
210 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
211
212 if( 0 <= topItem && topItem < (int)mMacros->GetItemCount())
213 {
214 // Workaround for scrolling being windows only.
215 // Try to scroll back to where we once were...
216 mMacros->EnsureVisible( (int)mMacros->GetItemCount() -1 );
217 mMacros->EnsureVisible( topItem );
218 // And then make sure whatever is selected is still visible...
219 if( bFound )
220 mMacros->EnsureVisible( item );
221 }
222}
223
224void ApplyMacroDialog::OnHelp(wxCommandEvent & WXUNUSED(event))
225{
226 const auto &page = GetHelpPageName();
227 HelpSystem::ShowHelp(this, page, true);
228}
229
230void ApplyMacroDialog::OnApplyToProject(wxCommandEvent & WXUNUSED(event))
231{
232 long item = mMacros->GetNextItem(-1,
233 wxLIST_NEXT_ALL,
234 wxLIST_STATE_SELECTED);
235
236 if (item == -1) {
237 AudacityMessageBox(XO("No macro selected"));
238 return;
239 }
240 ApplyMacroToProject( item );
241}
242
243CommandID ApplyMacroDialog::MacroIdOfName( const wxString & MacroName )
244{
245 wxString Temp = MacroName;
246 Temp.Replace(" ","");
247 Temp = wxString( "Macro_" ) + Temp;
248 return Temp;
249}
250
251// Apply macro, given its ID.
252// Does nothing if not found, rather than returning an error.
254{
255 for( int i=0;i<mMacros->GetItemCount();i++){
256 wxString name = mMacros->GetItemText(i);
257 if( MacroIdOfName( name ) == MacroID ){
258 ApplyMacroToProject( i, bHasGui );
259 return;
260 }
261 }
262}
263
264// Apply macro, given its number in the list.
265void ApplyMacroDialog::ApplyMacroToProject( int iMacro, bool bHasGui )
266{
267 wxString name = mMacros->GetItemText(iMacro);
268 if( name.empty() )
269 return;
270
271#ifdef OPTIONAL_ACTIVITY_WINDOW
272 wxDialogWrapper activityWin( this, wxID_ANY, GetTitle());
273 activityWin.SetName();
274 ShuttleGui S(&activityWin, eIsCreating);
275
276 S.StartHorizontalLay(wxCENTER, false);
277 {
278 S.StartStatic( {}, false); // deliberately not translated (!)
279 {
280 S.SetBorder(20);
281 S.AddFixedText(XO("Applying '%s' to current project")
282 .Format( name ) );
283 }
284 S.EndStatic();
285 }
286 S.EndHorizontalLay();
287
288 activityWin.Layout();
289 activityWin.Fit();
290 activityWin.CenterOnScreen();
291 // Avoid overlap with progress.
292 int x,y;
293 activityWin.GetPosition( &x, &y );
294 activityWin.Move(wxMax(0,x-300), 0);
295 activityWin.Show();
296
297 // Without this the newly created dialog may not show completely.
298 wxYield();
299#endif
300
301 //Since we intend to keep this dialog open, there is no reason to hide it
302 //and then show it again.
303 //if( bHasGui )
304 // Hide();
305
306 gPrefs->Write(wxT("/Batch/ActiveMacro"), name);
307 gPrefs->Flush();
308
310
311 // The disabler must get deleted before the EndModal() call. Otherwise,
312 // the menus on OSX will remain disabled.
313 bool success;
314 {
315#ifdef OPTIONAL_ACTIVITY_WINDOW
316 wxWindowDisabler wd(&activityWin);
317#endif
318 success = GuardedCall< bool >(
319 [this]{ return mMacroCommands.ApplyMacro(mCatalog); } );
320 }
321
322 if( !bHasGui )
323 return;
324
325 Show();
326 Raise();
327}
328
329void ApplyMacroDialog::OnApplyToFiles(wxCommandEvent & WXUNUSED(event))
330{
331 long item = mMacros->GetNextItem(-1,
332 wxLIST_NEXT_ALL,
333 wxLIST_STATE_SELECTED);
334 if (item == -1) {
335 AudacityMessageBox( XO("No macro selected") );
336 return;
337 }
338
339 wxString name = mMacros->GetItemText(item);
340 gPrefs->Write(wxT("/Batch/ActiveMacro"), name);
341 gPrefs->Flush();
342
344 if (!TrackList::Get( *project ).empty()) {
346 XO("Please save and close the current project first.") );
347 return;
348 }
349
350 // This insures that we start with an empty and temporary project
353
354 auto prompt = XO("Select file(s) for batch processing...");
355
356 const auto fileTypes = Importer::Get().GetFileTypes();
357
358 auto path = FileNames::FindDefaultPath(FileNames::Operation::Open);
359 FileDialogWrapper dlog(this,
360 prompt,
361 path,
362 wxT(""),
363 fileTypes,
364 wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER);
365
367 if (dlog.ShowModal() != wxID_OK) {
368 Raise();
369 return;
370 }
371 Raise();
372
373 wxArrayString files;
374 dlog.GetPaths(files);
375
376 files.Sort();
377
378 wxDialogWrapper activityWin(this, wxID_ANY, Verbatim( GetTitle() ),
379 wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER
380 );
381 activityWin.SetName();
382 ShuttleGui S(&activityWin, eIsCreating);
383
384 wxListCtrl * fileList = NULL;
385
386 S.StartVerticalLay(1);
387 {
388 S.StartStatic(XO("Applying..."), 1);
389 {
390 auto imageList = std::make_unique<wxImageList>(9, 16);
391 imageList->Add(wxIcon(empty9x16_xpm));
392 imageList->Add(wxIcon(arrow_xpm));
393
394 fileList = S.Id(CommandsListID)
395 .Style( wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
396 wxLC_SINGLE_SEL)
397 .AddListControlReportMode( { XO("File") } );
398 // AssignImageList takes ownership
399 fileList->AssignImageList(imageList.release(), wxIMAGE_LIST_SMALL);
400 }
401 S.EndStatic();
402
403 S.StartHorizontalLay(wxCENTER, 0);
404 {
405 S.Id(wxID_CANCEL).AddButton(XXO("&Cancel"));
406 }
407 S.EndHorizontalLay();
408 }
409 S.EndVerticalLay();
410
411 int i;
412 for (i = 0; i < (int)files.size(); i++ ) {
413 fileList->InsertItem(i, files[i], i == 0);
414 }
415
416 // Set the column size for the files list.
417 fileList->SetColumnWidth(0, wxLIST_AUTOSIZE);
418
419 int width = wxMin( fileList->GetColumnWidth(0), 1000);
420 wxSize sz = fileList->GetClientSize();
421 if (sz.GetWidth() < width ) {
422 sz.SetWidth(width);
423 if (sz.GetHeight() < width *0.7)
424 sz.SetHeight(width * 0.7);
425 fileList->SetInitialSize(sz);
426 }
427
428 activityWin.Layout();
429 activityWin.Fit();
430 activityWin.CenterOnScreen();
431 // Avoid overlap with progress.
432 int x,y;
433 activityWin.GetPosition( &x, &y );
434 activityWin.Move(wxMax(0,x-300), 0);
435 activityWin.Show();
436
437 // Without this the newly created dialog may not show completely.
438 wxYield();
439 // We could avoid hiding, but there are many dialogs on screen,
440 // and hiding this one temporarily has some advantages.
441 Hide();
442
444 {
445 auto &globalClipboard = Clipboard::Get();
446
447 // DV: Macro invocation on file will reset the project to the
448 // initial state. There is a possibility, that clipboard will contain
449 // references to the data removed
450 if (globalClipboard.Project().lock().get() == project)
451 globalClipboard.Clear();
452
453 // Move global clipboard contents aside temporarily
455
456 wxWindowDisabler wd(&activityWin);
457 for (i = 0; i < (int)files.size(); i++) {
458 if (i > 0) {
459 //Clear the arrow in previous item.
460 fileList->SetItemImage(i - 1, 0, 0);
461 }
462 fileList->SetItemImage(i, 1, 1);
463 fileList->EnsureVisible(i);
464
465 auto success = GuardedCall<bool>([&] {
466 ProjectFileManager::Get(*project).Import(files[i]);
470 return false;
471
472 if (!activityWin.IsShown() || mAbort)
473 return false;
474
475 return true;
476 });
477
478 // Ensure project is completely reset
480 // Bug2567:
481 // Must also destroy the clipboard, to be sure sample blocks are
482 // all freed and their ids can be reused safely in the next pass
483 globalClipboard.Clear();
484
485 if (!success)
486 break;
487 }
488 }
489
490 Show();
491 Raise();
492}
493
494void ApplyMacroDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
495{
496 Hide();
497}
498
500#include <wx/textdlg.h>
501#include "BatchCommandDialog.h"
502
503enum {
504 AddButtonID = 10000,
511
513
519
520// MacrosListID 7005
521// CommandsListID, 7002
522// Re-Use IDs from ApplyMacroDialog.
525};
526
527BEGIN_EVENT_TABLE(MacrosWindow, ApplyMacroDialog)
530 EVT_LIST_BEGIN_LABEL_EDIT(MacrosListID, MacrosWindow::OnMacrosBeginEdit)
531 EVT_LIST_END_LABEL_EDIT(MacrosListID, MacrosWindow::OnMacrosEndEdit)
539
542 EVT_SIZE(MacrosWindow::OnSize)
543
544 EVT_LIST_ITEM_ACTIVATED(CommandsListID, MacrosWindow::OnCommandActivated)
550
554
555 EVT_KEY_DOWN(MacrosWindow::OnKeyDown)
557
558enum {
562};
563
566 wxWindow * parent, AudacityProject &project, bool bExpanded):
567 ApplyMacroDialog(parent, project, true)
568 , mProject{ project }
569{
570 mbExpanded = bExpanded;
571 auto Title = WindowTitle();
572 SetLabel( Title ); // Provide visual label
573 SetName( Title ); // Provide audible label
574 SetTitle( Title );
575
576 mChanged = false;
578
579 if( mbExpanded )
580 Populate();
581 else
583}
584
586{
587}
588
591{
592 //------------------------- Main section --------------------
593 ShuttleGui S(this, eIsCreating);
595 // ----------------------- End of main section --------------
596
597 // Get and validate the currently active macro
598 mActiveMacro = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxT(""));
599 // Go populate the macros list.
601
602 // We have a bare list. We need to add columns and content.
603 PopulateList();
604
605 // Layout and set minimum size of window
606 Layout();
607 Fit();
608 SetSizeHints(GetSize());
609
610 // Size and place window
611 SetSize(std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_X) * 3 / 4, 800),
612 std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) * 4 / 5, 400));
613 Center();
614
615 // Set the column size for the macros list.
616 wxSize sz = mMacros->GetClientSize();
617 mMacros->SetColumnWidth(0, sz.x);
618
619 // Size columns properly
620 FitColumns();
621}
622
625{
626 S.StartHorizontalLay(wxEXPAND, 1);
627 {
628 S.StartStatic(XO("Select Macro"),0);
629 {
630 S.StartHorizontalLay(wxEXPAND,1);
631 {
632 mMacros = S.Id(MacrosListID).Prop(1)
633 .Style( wxLC_REPORT | wxLC_HRULES
634 | wxLC_SINGLE_SEL | wxLC_EDIT_LABELS)
635 // i18n-hint: This is the heading for a column in the edit macros dialog
636 .AddListControlReportMode( { XO("Macro") } );
637 S.StartVerticalLay(wxALIGN_TOP, 0);
638 {
639 S.Id(AddButtonID).AddButton(XXO("&New"), wxALIGN_LEFT);
640 mRemove = S.Id(RemoveButtonID).AddButton(XXO("Remo&ve"), wxALIGN_LEFT);
641 mRename = S.Id(RenameButtonID).AddButton(XXO("&Rename..."), wxALIGN_LEFT);
642 mRestore = S.Id(RestoreButtonID).AddButton(XXO("Re&store"), wxALIGN_LEFT);
643 mImport = S.Id(ImportButtonID).AddButton(XO("I&mport..."), wxALIGN_LEFT);
644 mExport = S.Id(ExportButtonID).AddButton(XO("E&xport..."), wxALIGN_LEFT);
645 }
646 S.EndVerticalLay();
647 }
648 S.EndHorizontalLay();
649 }
650 S.EndStatic();
651
652 S.StartStatic(XO("Edit Steps"), true);
653 {
654 S.StartHorizontalLay(wxEXPAND,1);
655 {
657 .Style( wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
658 wxLC_SINGLE_SEL)
659 .AddListControlReportMode({
660 /* i18n-hint: This is the number of the command in the list */
661 { XO("Num"), wxLIST_FORMAT_RIGHT },
662 { XO("Command "), wxLIST_FORMAT_RIGHT },
663 { XO("Parameters"), wxLIST_FORMAT_LEFT }
664 });
665
666 S.StartVerticalLay(wxALIGN_TOP, 0);
667 {
668 S.Id(InsertButtonID).AddButton(XXO("&Insert"), wxALIGN_LEFT);
669 mEdit = S.Id(EditButtonID).AddButton(XXO("&Edit..."), wxALIGN_LEFT);
670 S.Id(DeleteButtonID).AddButton(XXO("De&lete"), wxALIGN_LEFT);
671 S.Id(UpButtonID).AddButton(XXO("Move &Up"), wxALIGN_LEFT);
672 S.Id(DownButtonID).AddButton(XXO("Move &Down"), wxALIGN_LEFT);
673 mSave = S.Id(SaveButtonID).AddButton(XO("&Save"), wxALIGN_LEFT);
674 mSave->Enable( mChanged );
675 }
676 S.EndVerticalLay();
677 }
678 S.EndHorizontalLay();
679 }
680 S.EndStatic();
681 }
682 S.EndHorizontalLay();
683
684 S.StartHorizontalLay(wxEXPAND, 0);
685 {
686 /* i18n-hint: The Shrink button makes the dialog smaller, with less in it */
687 mResize = S.Id(ShrinkID).AddButton(XXO("Shrin&k"));
688 // Using variable text just to get the positioning options.
689 S.Prop(0).AddVariableText(
690 XO("Apply Macro to:"), false, wxALL | wxALIGN_CENTRE_VERTICAL );
691 wxButton* btn = S.Id(ApplyToProjectID)
692 .Name(XO("Apply macro to project"))
693 .AddButton(XXO("&Project"));
694#if wxUSE_ACCESSIBILITY
695 // so that name can be set on a standard control
696 btn->SetAccessible(safenew WindowAccessible(btn));
697#endif
698
699 btn = S.Id(ApplyToFilesID)
700 .Name(XO("Apply macro to files..."))
701 .AddButton(XXO("&Files..."));
702#if wxUSE_ACCESSIBILITY
703 // so that name can be set on a standard control
704 btn->SetAccessible(safenew WindowAccessible(btn));
705#endif
706 S.AddSpace( 10,10,1 );
707 // Bug 2524 OK button does much the same as cancel, so remove it.
708 // OnCancel prompts you if there has been a change.
709 // OnOK saves without prompting.
710 // That difference is too slight to merit a button, and with the OK
711 // button, people might expect the dialog to apply the macro too.
712 S.AddStandardButtons( /*eOkButton |*/ eCloseButton | eHelpButton);
713 }
714
715 S.EndHorizontalLay();
716
717
718 return;
719}
720
723{
724 int topItem = mList->GetTopItem();
725 mList->DeleteAllItems();
726
727 for (int i = 0; i < mMacroCommands.GetCount(); i++) {
730 }
731 /*i18n-hint: This is the last item in a list.*/
732 AddItem(_("- END -"), wxT(""));
733
734 // Select the name in the list...this will fire an event.
735 if (mSelectedCommand >= (int)mList->GetItemCount()) {
737 }
738 mList->SetItemState(mSelectedCommand,
739 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
740 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
741 if( 0 <= topItem && topItem < (int)mList->GetItemCount())
742 {
743 // Workaround for scrolling being windows only.
744 // Try to scroll back to where we once were...
745 mList->EnsureVisible( (int)mList->GetItemCount() -1 );
746 mList->EnsureVisible( topItem );
747 // And then make sure whatever is selected is still visible...
748 if (mSelectedCommand >= 0) {
749 mList->EnsureVisible( mSelectedCommand );
750 }
751 }
752}
753
755void MacrosWindow::AddItem(const CommandID &Action, const wxString &Params)
756{
758 auto friendlyName = entry != mCatalog.end()
759 ? entry->name.StrippedTranslation()
760 :
761 // uh oh, using GET to expose an internal name to the user!
762 // in default of any better friendly name
763 Action.GET();
764
765 int i = mList->GetItemCount();
766
767 mList->InsertItem(i, wxString::Format(wxT(" %02i"), i + 1));
768 mList->SetItem(i, ActionColumn, friendlyName );
769 mList->SetItem(i, ParamsColumn, Params );
770}
771
773{
774 // OK even on mac, as dialog is modal.
775 auto p = &mProject;
777}
778
779void MacrosWindow::UpdateDisplay( bool bExpanded )
780{
781 // If we failed to save changes, we abandon the attempt to
782 // change the expand/shrink state of the GUI.
783 if( !SaveChanges() )
784 return;
785
786 mbExpanded = bExpanded;
787
788 mChanged = false;
789 // if we try to access the about to be destroyed mSave button
790 // inappropriately, we need to crash rather than (sometimes) silently
791 // succeed.
792 mSave = nullptr;
793
794 DestroyChildren();
795 SetSizer( nullptr );
796
798 SetMinSize( wxSize( 200,200 ));
799
800 // Get and set position for optical stability.
801 // Expanded and shrunk dialogs 'stay where they were'.
802 // That's OK , and what we want, even if we exapnd off-screen.
803 // We won't shrink to being off-screen, since the shrink button
804 // was clicked, so must have been on screen.
805 wxPoint p = GetPosition( );
806 if( mbExpanded )
807 Populate();
808 else
810 SetPosition( p );
811 mResize->SetFocus();
812
813 auto Title = WindowTitle();
814 SetLabel( Title ); // Provide visual label
815 SetName( Title ); // Provide audible label
816 SetTitle( Title );
817}
818
819void MacrosWindow::OnExpand(wxCommandEvent &WXUNUSED(event))
820{ UpdateDisplay( true );}
821
822void MacrosWindow::OnShrink(wxCommandEvent &WXUNUSED(event))
823{
824 if( ChangeOK() )
825 UpdateDisplay( false );
826}
827
828
830{
831 if (mChanged) {
832 int id;
833
834 auto title = XO("%s changed").Format( mActiveMacro );
835 auto msg = XO("Do you want to save the changes?");
836
838 msg,
839 title,
840 wxYES_NO | wxCANCEL);
841 if (id == wxCANCEL) {
842 return false;
843 }
844
845 if (id == wxYES) {
847 return false;
848 }
849 }
850
851 mChanged = false;
852 mSave->Enable( mChanged );
853 }
854
855 return true;
856}
858void MacrosWindow::OnMacroSelected(wxListEvent & event)
859{
860 if (!ChangeOK()) {
861 event.Veto();
862 return;
863 }
864
865 int item = event.GetIndex();
866
867 mActiveMacro = mMacros->GetItemText(item);
869}
870
872{
874 if( !mbExpanded )
875 return;
876
878 mRemove->Disable();
879 mRename->Disable();
880 mRestore->Enable();
881 }
882 else {
883 mRemove->Enable();
884 mRename->Enable();
885 mRestore->Disable();
886 }
887
888 PopulateList();
889}
890
892void MacrosWindow::OnListSelected(wxListEvent &event)
893{
894 const auto &command = mCatalog.ByTranslation(mList->GetItemText(event.GetIndex(), ActionColumn));
895
896 if (command != mCatalog.end())
897 {
899 PluginID ID = em.GetEffectByIdentifier(command->name.Internal());
900
901 mEdit->Enable(!ID.empty());
902 }
903
904
905 FitColumns();
906}
907
909void MacrosWindow::OnSize(wxSizeEvent & WXUNUSED(event))
910{
911 // Refresh the layout and re-fit the columns.
912 Layout();
913 if( !mbExpanded )
914 return;
915 FitColumns();
916}
917
919{
920
921#if defined(__WXMAC__)
922 // wxMac uses a hard coded width of 150 when wxLIST_AUTOSIZE_USEHEADER
923 // is specified, so we calculate the width ourselves. This method may
924 // work equally well on other platforms.
925 for (size_t c = 0; c < mList->GetColumnCount(); c++) {
926 wxListItem info;
927 int width;
928
929 mList->SetColumnWidth(c, wxLIST_AUTOSIZE);
930 info.Clear();
931 info.SetId(c);
932 info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_WIDTH);
933 mList->GetColumn(c, info);
934
935 mList->GetTextExtent(info.GetText(), &width, NULL);
936 width += 2 * 4; // 2 * kItemPadding - see listctrl_mac.cpp
937 width += 16; // kIconWidth - see listctrl_mac.cpp
938
939 mList->SetColumnWidth(c, wxMax(width, mList->GetColumnWidth(c)));
940 }
941
942 // Looks strange, but it forces the horizontal scrollbar to get
943 // drawn. If not done, strange column sizing can occur if the
944 // user attempts to resize the columns.
945 mList->SetClientSize(mList->GetClientSize());
946#else
947 mList->SetColumnWidth(0, wxLIST_AUTOSIZE_USEHEADER);
948 mList->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER);
949 mList->SetColumnWidth(2, wxLIST_AUTOSIZE);
950#endif
951
952 int bestfit = mList->GetColumnWidth(2);
953 int clientsize = mList->GetClientSize().GetWidth();
954 int col0 = mList->GetColumnWidth(0);
955 int col1 = mList->GetColumnWidth(1);
956 bestfit = (bestfit > clientsize-col0-col1)? bestfit : clientsize-col0-col1;
957 mList->SetColumnWidth(2, bestfit);
958
959}
960
962void MacrosWindow::OnMacrosBeginEdit(wxListEvent &event)
963{
964 int itemNo = event.GetIndex();
965
966 wxString macro = mMacros->GetItemText(itemNo);
967
968 if (mMacroCommands.IsFixed(macro)) {
969 wxBell();
970 event.Veto();
971 }
972 if( mMacroBeingRenamed.IsEmpty())
973 mMacroBeingRenamed = macro;
974}
975
977void MacrosWindow::OnMacrosEndEdit(wxListEvent &event)
978{
979 if (event.IsEditCancelled()) {
981 return;
982 }
983
984 if( mMacroBeingRenamed.IsEmpty())
985 return;
986
987 wxString newname = event.GetLabel();
988
991 mActiveMacro = newname;
994 UpdateMenus();
995 event.Veto();
996}
997
999void MacrosWindow::OnAdd(wxCommandEvent & WXUNUSED(event))
1000{
1001 // Similar to Bug 2284 we may need to save a changed macro.
1002 if (!ChangeOK()) {
1003 return;
1004 }
1005
1006 while (true) {
1008 XO("Enter name of new macro"),
1009 XO("Name of new macro"));
1010 d.SetName(d.GetTitle());
1011 wxString name;
1012
1013 if (d.ShowModal() == wxID_CANCEL) {
1014 Raise();
1015 return;
1016 }
1017 Raise();
1018
1019 name = d.GetValue().Strip(wxString::both);
1020
1021 if (name.length() == 0) {
1023 XO("Name must not be blank"),
1024 WindowTitle(),
1025 wxOK | wxICON_ERROR,
1026 this);
1027 continue;
1028 }
1029
1030 if (name.Contains(wxFILE_SEP_PATH) ||
1031 name.Contains(wxFILE_SEP_PATH_UNIX)) {
1033 /*i18n-hint: The %c will be replaced with 'forbidden characters', like '/' and '\'.*/
1034 XO("Names may not contain '%c' and '%c'")
1035 .Format(wxFILE_SEP_PATH, wxFILE_SEP_PATH_UNIX),
1036 WindowTitle(),
1037 wxOK | wxICON_ERROR,
1038 this);
1039 continue;
1040 }
1041
1043
1045
1047 UpdateMenus();
1048
1049 break;
1050 }
1051}
1052
1054void MacrosWindow::OnRemove(wxCommandEvent & WXUNUSED(event))
1055{
1056 long item = mMacros->GetNextItem(-1,
1057 wxLIST_NEXT_ALL,
1058 wxLIST_STATE_SELECTED);
1059 if (item == -1) {
1060 return;
1061 }
1062
1063 wxString name = mMacros->GetItemText(item);
1065 this,
1066 /*i18n-hint: %s will be replaced by the name of a file.*/
1067 XO("Are you sure you want to delete %s?").Format( name ),
1068 Verbatim( GetTitle() ),
1069 wxYES_NO | wxICON_QUESTION );
1070 if (m.ShowModal() == wxID_NO) {
1071 Raise();
1072 return;
1073 }
1074 Raise();
1075
1077
1078 item++;
1079 if (item >= (mMacros->GetItemCount() - 1) && item >= 0) {
1080 item--;
1081 }
1082
1083 // Bug 2284. The macro we have just removed might have been
1084 // changed. Since we've just deleted the macro, we should
1085 // forget about that change.
1086 mChanged = false;
1087 mSave->Enable( mChanged );
1088 mActiveMacro = mMacros->GetItemText(item);
1089
1091 UpdateMenus();
1092}
1093
1095void MacrosWindow::OnRename(wxCommandEvent & WXUNUSED(event))
1096{
1097 long item = mMacros->GetNextItem(-1,
1098 wxLIST_NEXT_ALL,
1099 wxLIST_STATE_SELECTED);
1100 if (item == -1) {
1101 return;
1102 }
1103
1104 mMacros->EditLabel(item);
1105 UpdateMenus();
1106}
1107
1109void MacrosWindow::OnRestore(wxCommandEvent & WXUNUSED(event))
1110{
1112
1113 mChanged = true;
1114 mSave->Enable( mChanged );
1115
1116 PopulateList();
1117}
1118
1120void MacrosWindow::OnImport(wxCommandEvent & WXUNUSED(event))
1121{
1122 if (!ChangeOK()) {
1123 return;
1124 }
1125
1126 long item = mMacros->GetNextItem(-1,
1127 wxLIST_NEXT_ALL,
1128 wxLIST_STATE_SELECTED);
1129 if (item == -1) {
1130 return;
1131 }
1132
1133 wxString name = mMacros->GetItemText(item);
1134
1135 name = mMacroCommands.ReadMacro({}, this);
1136 if (name == wxEmptyString) {
1137 return;
1138 }
1139
1141
1143 UpdateMenus();
1144}
1145
1147void MacrosWindow::OnExport(wxCommandEvent & WXUNUSED(event))
1148{
1149 long item = mMacros->GetNextItem(-1,
1150 wxLIST_NEXT_ALL,
1151 wxLIST_STATE_SELECTED);
1152 if (item == -1) {
1153 return;
1154 }
1155
1156 mMacroCommands.WriteMacro(mMacros->GetItemText(item), this);
1157}
1158
1159void MacrosWindow::OnSave(wxCommandEvent & WXUNUSED(event))
1160{
1161 SaveChanges();
1162}
1163
1164
1167void MacrosWindow::OnCommandActivated(wxListEvent & WXUNUSED(event))
1168{
1169 wxCommandEvent dummy;
1170 OnEditCommandParams( dummy );
1171}
1172
1174void MacrosWindow::OnInsert(wxCommandEvent & WXUNUSED(event))
1175{
1176 long item = mList->GetNextItem(-1,
1177 wxLIST_NEXT_ALL,
1178 wxLIST_STATE_SELECTED);
1179 if (item == -1) {
1180 item = mList->GetItemCount()-1;
1181 }
1182 InsertCommandAt( item );
1183}
1184
1186{
1187 if (item == -1) {
1188 return;
1189 }
1190
1191 MacroCommandDialog d(this, wxID_ANY, mProject);
1192
1193 if (!d.ShowModal()) {
1194 Raise();
1195 return;
1196 }
1197 Raise();
1198
1199 if(!d.mSelectedCommand.empty())
1200 {
1203 item);
1204 mChanged = true;
1205 mSave->Enable( mChanged );
1206
1207 mSelectedCommand = item + 1;
1208 PopulateList();
1209 }
1210
1211}
1212
1213void MacrosWindow::OnEditCommandParams(wxCommandEvent & WXUNUSED(event))
1214{
1215 int item = mList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1216
1217 // LAST command in list is END.
1218 // If nothing selected, add at END.
1219 // If END selected, add at END.
1220 // When adding at end we use InsertCommandAt, so that a new command
1221 // can be chosen.
1222 int lastItem = mList->GetItemCount()-1;
1223 if( (item<0) || (item+1) == mList->GetItemCount() )
1224 {
1225 InsertCommandAt( lastItem );
1226 return;
1227 }
1228
1229 // Just edit the parameters, and not the command.
1230 auto command = mMacroCommands.GetCommand(item);
1231 wxString params = mMacroCommands.GetParams(item);
1232 wxString oldParams = params;
1233
1234 params = MacroCommands::PromptForParamsFor(command, params, *this).Trim();
1235 Raise();
1236
1237 if (oldParams == params)
1238 return; // They did not actually make any changes..
1239
1241 mMacroCommands.AddToMacro(command,
1242 params,
1243 item);
1244
1245 mChanged = true;
1246 mSave->Enable( mChanged );
1247
1248 mSelectedCommand = item;
1249 PopulateList();
1250}
1251
1253void MacrosWindow::OnDelete(wxCommandEvent & WXUNUSED(event))
1254{
1255 long item = mList->GetNextItem(-1,
1256 wxLIST_NEXT_ALL,
1257 wxLIST_STATE_SELECTED);
1258 if (item == -1 || item + 1 == mList->GetItemCount()) {
1259 return;
1260 }
1261
1263
1264 mChanged = true;
1265 mSave->Enable( mChanged );
1266
1267 if (item >= (mList->GetItemCount() - 2) && item >= 0) {
1268 item--;
1269 }
1270 mSelectedCommand = item;
1271 PopulateList();
1272}
1273
1275void MacrosWindow::OnUp(wxCommandEvent & WXUNUSED(event))
1276{
1277 long item = mList->GetNextItem(-1,
1278 wxLIST_NEXT_ALL,
1279 wxLIST_STATE_SELECTED);
1280 if (item == -1 || item == 0 || item + 1 == mList->GetItemCount()) {
1281 return;
1282 }
1283
1286 item - 1);
1288
1289 mChanged = true;
1290 mSave->Enable( mChanged );
1291
1292 mSelectedCommand = item - 1;
1293 PopulateList();
1294}
1295
1297void MacrosWindow::OnDown(wxCommandEvent & WXUNUSED(event))
1298{
1299 long item = mList->GetNextItem(-1,
1300 wxLIST_NEXT_ALL,
1301 wxLIST_STATE_SELECTED);
1302 if (item == -1 || item + 2 >= mList->GetItemCount()) {
1303 return;
1304 }
1305
1308 item + 2);
1310
1311 mChanged = true;
1312 mSave->Enable( mChanged );
1313
1314 mSelectedCommand = item + 1;
1315 PopulateList();
1316}
1317
1318void MacrosWindow::OnApplyToProject(wxCommandEvent & event)
1319{
1320 if( !SaveChanges() )
1321 return;
1323}
1324
1325void MacrosWindow::OnApplyToFiles(wxCommandEvent & event)
1326{
1327 if( !SaveChanges() )
1328 return;
1330}
1331
1333 gPrefs->Write(wxT("/Batch/ActiveMacro"), mActiveMacro);
1334 gPrefs->Flush();
1335
1336 if (mChanged) {
1338 return false;
1339 }
1340 }
1341
1342 mChanged = false;
1343 if( mSave )
1344 mSave->Enable( mChanged );
1345
1346 return true;
1347}
1348
1350void MacrosWindow::OnOK(wxCommandEvent & WXUNUSED(event))
1351{
1352 if( !SaveChanges() )
1353 return;
1354 Hide();
1355 //EndModal(true);
1356}
1357
1359void MacrosWindow::OnCancel(wxCommandEvent &WXUNUSED(event))
1360{
1361 bool bWasChanged = mChanged;
1362 if (!ChangeOK()) {
1363 return;
1364 }
1365 // If we've rejected a change, we need to restore the display
1366 // of the active macro.
1367 // That's because next time we open this dialog we want to see the
1368 // unedited macro.
1369 if( bWasChanged )
1371 Hide();
1372}
1373
1375void MacrosWindow::OnKeyDown(wxKeyEvent &event)
1376{
1377 if (event.GetKeyCode() == WXK_DELETE) {
1378 wxLogDebug(wxT("wxKeyEvent"));
1379 }
1380
1381 event.Skip();
1382}
1383
1385{
1387}
1388
1389// PrefsListener implementation
1391{
1393}
1394
1395// The rest of this file installs hooks
1396
1397#include "CommonCommandFlags.h"
1398#include "CommandContext.h"
1399#include "effects/EffectManager.h"
1400namespace {
1401
1402AttachedWindows::RegisteredFactory sMacrosWindowKey{
1403 []( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
1404 auto &window = GetProjectFrame(parent);
1405 return safenew MacrosWindow(
1406 &window, parent, true
1407 );
1408 }
1409};
1410
1411using MacroID = wxString;
1412
1414 const CommandContext& context, const MacroID& Name);
1415
1417{
1418 auto& commandManager = CommandManager::Get(context.project);
1419 switch (commandManager.mLastToolRegistration) {
1421 {
1422 auto lastEffect = commandManager.mLastTool;
1423 if (!lastEffect.empty())
1424 {
1426 lastEffect, context, commandManager.mRepeatToolFlags);
1427 }
1428 }
1429 break;
1432 commandManager.mLastToolRegisteredId);
1433 break;
1435 OnApplyMacroDirectlyByName(context, commandManager.mLastTool);
1436 break;
1437 }
1438}
1439
1440void OnManageMacros(const CommandContext &context )
1441{
1442 auto &project = context.project;
1443 CommandManager::Get(project).RegisterLastTool(context); //Register Macros as Last Tool
1444 auto macrosWindow = &GetAttachedWindows(project)
1445 .AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey );
1446 if (macrosWindow) {
1447 macrosWindow->Show();
1448 macrosWindow->Raise();
1449 macrosWindow->UpdateDisplay( true );
1450 }
1451}
1452
1454{
1455 auto &project = context.project;
1456 CommandManager::Get(project).RegisterLastTool(context); //Register Palette as Last Tool
1457 auto macrosWindow = &GetAttachedWindows(project)
1458 .AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey );
1459 if (macrosWindow) {
1460 macrosWindow->Show();
1461 macrosWindow->Raise();
1462 macrosWindow->UpdateDisplay( false );
1463 }
1464}
1465
1467{
1468 const MacroID& Name = context.parameter.GET();
1469 OnApplyMacroDirectlyByName(context, Name);
1470}
1471
1472void OnApplyMacroDirectlyByName(const CommandContext& context, const MacroID& Name)
1473
1474{
1475 auto &project = context.project;
1476 auto &window = GetProjectFrame(project);
1477 //wxLogDebug( "Macro was: %s", context.parameter);
1478 ApplyMacroDialog dlg( &window, project );
1479 //const auto &Name = context.parameter;
1480
1481// We used numbers previously, but macros could get renumbered, making
1482// macros containing macros unpredictable.
1483#ifdef MACROS_BY_NUMBERS
1484 long item=0;
1485 // Take last three letters (of e.g. Macro007) and convert to a number.
1486 Name.Mid( Name.length() - 3 ).ToLong( &item, 10 );
1487 dlg.ApplyMacroToProject( item, false );
1488#else
1489 dlg.ApplyMacroToProject( Name, false );
1490#endif
1491 /* i18n-hint: %s will be the name of the macro which will be
1492 * repeated if this menu item is chosen */
1494
1497 auto shortDesc = em.GetCommandName(Name);
1498 auto& undoManager = UndoManager::Get(project);
1499 auto& commandManager = CommandManager::Get(project);
1500 int cur = undoManager.GetCurrentState();
1501 if (undoManager.UndoAvailable()) {
1502 undoManager.GetShortDescription(cur, &desc);
1503 commandManager.Modify(wxT("RepeatLastTool"), XXO("&Repeat %s")
1504 .Format(desc));
1505 auto& commandManager = CommandManager::Get(project);
1506 commandManager.mLastTool = Name;
1507 commandManager.mLastToolRegistration =
1509 }
1510
1511}
1512
1514{
1515 using namespace MenuRegistry;
1516 auto names = MacroCommands::GetNames(); // these names come from filenames
1517 for (const auto &name : names) {
1520 Verbatim(name), // file name verbatim
1522 flags,
1524 ));
1525 }
1526}
1527
1530 [](const AudacityProject &project) {
1531 auto& commandManager = CommandManager::Get(project);
1532 if (commandManager.mLastToolRegistration ==
1534 return true;
1535 return !commandManager.mLastTool.empty();
1536 }
1537 }; return flag;
1538}
1539}
1540
1541using namespace MenuRegistry;
1542
1544{
1545 static auto items = std::shared_ptr{
1546 Items( "Macros",
1547 Section( "RepeatLast",
1548 // Delayed evaluation:
1550 {
1551 const auto &lastTool = CommandManager::Get(project).mLastTool;
1552 TranslatableString buildMenuLabel;
1553 if (!lastTool.empty())
1554 buildMenuLabel = XO("Repeat %s")
1555 .Format( EffectManager::Get().GetCommandName(lastTool) );
1556 else
1557 buildMenuLabel = XO("Repeat Last Tool");
1558
1559 return Command( wxT("RepeatLastTool"), buildMenuLabel,
1563 Options{}.IsGlobal() );
1564 }
1565 ),
1566
1567 Command( wxT("ManageMacros"), XXO("&Macro Manager"),
1569
1570 Menu( wxT("Macros"), XXO("&Apply Macro"),
1571 // Palette has no access key to ensure first letter navigation of
1572 // sub menu
1573 Section( "",
1574 Command( wxT("ApplyMacrosPalette"), XXO("Palette..."),
1576 ),
1577
1578 Section( "",
1579 // Delayed evaluation:
1580 [](AudacityProject&) {
1581 auto result = Items("");
1583 return result;
1584 }
1585 )
1586 )
1587 ) };
1588 return items;
1589}
1590
1592
1594{
1595 // These are the more useful to VI user Scriptables.
1596 static auto menu = std::shared_ptr{
1597 // i18n-hint: Scriptables are commands normally used from Python, Perl etc.
1598 Menu( wxT("Scriptables1"), XXO("Script&ables I") )
1599 };
1600 return menu;
1601}
1602
1604 wxT("Optional/Extra/Part2")
1605};
1606
1608{
1609 // Less useful to VI users.
1610 static auto menu = std::shared_ptr{
1611 // i18n-hint: Scriptables are commands normally used from Python, Perl etc.
1612 Menu( wxT("Scriptables2"), XXO("Scripta&bles II") )
1613 };
1614 return menu;
1615}
1616
1618 wxT("Optional/Extra/Part2")
1619};
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
#define ApplyToFilesID
AttachedItem sAttachment1
auto ExtraScriptablesIMenu()
AttachedItem sAttachment3
AttachedItem sAttachment2
auto ExtraScriptablesIIMenu()
#define MacrosListID
@ ActionColumn
@ ParamsColumn
@ ItemNumberColumn
#define CommandsListID
#define ApplyToProjectID
#define MacrosPaletteTitle
#define ShrinkID
#define ExpandID
auto PluginMenuItems()
#define ManageMacrosTitle
@ SaveButtonID
@ UpButtonID
@ ImportButtonID
@ DownButtonID
@ RestoreButtonID
@ RenameButtonID
@ AddButtonID
@ EditButtonID
@ DefaultsButtonID
@ RemoveButtonID
@ ApplyToProjectButtonID
@ DeleteButtonID
@ InsertButtonID
@ ApplyToFilesButtonID
@ ExportButtonID
wxString PluginID
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:30
const ReservedCommandFlag & AudioIONotBusyFlag()
int min(int a, int b)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
EffectDistortionSettings params
Definition: Distortion.cpp:77
const TranslatableString name
Definition: Distortion.cpp:76
EVT_LIST_ITEM_SELECTED(CurvesListID, EqualizationCurvesDialog::OnListSelectionChange) EVT_LIST_ITEM_DESELECTED(CurvesListID
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
static ProjectFileIORegistry::AttributeWriterEntry entry
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:10
static const auto title
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
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 ...
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
accessors for certain important windows associated with each project
@ eIsCreating
Definition: ShuttleGui.h:37
@ eCloseButton
Definition: ShuttleGui.h:619
@ eHelpButton
Definition: ShuttleGui.h:613
static TranslatableStrings names
Definition: TagsEditor.cpp:153
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 std::once_flag flag
Shows progress in executing commands in MacroCommands.
wxButton * mResize
Provides list of available commands.
virtual void OnApplyToFiles(wxCommandEvent &event)
MacroCommands mMacroCommands
AudacityProject & mProject
wxListCtrl * mMacros
void ApplyMacroToProject(int iMacro, bool bHasGui=true)
virtual void OnCancel(wxCommandEvent &event)
virtual void OnApplyToProject(wxCommandEvent &event)
const MacroCommandsCatalog mCatalog
virtual void OnHelp(wxCommandEvent &event)
void PopulateOrExchange(ShuttleGui &S)
Defines the dialog and does data exchange with it.
virtual ManualPageID GetHelpPageName()
static CommandID MacroIdOfName(const wxString &MacroName)
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Wrap wxTextEntryDialog so that caption IS translatable.
static Clipboard & Get()
Definition: Clipboard.cpp:28
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
CommandParameter parameter
AudacityProject & project
void RegisterLastTool(const CommandContext &context)
PluginID mLastTool
void DoRepeatProcess(const CommandContext &context, int)
static CommandManager & Get(AudacityProject &project)
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:48
static EffectManager & Get()
TranslatableString GetCommandName(const PluginID &ID)
const PluginID & GetEffectByIdentifier(const CommandID &strTarget)
virtual void GetPaths(wxArrayString &paths) const
virtual void SetFilterIndex(int filterIndex)
virtual int ShowModal()
Abstract base class used in importing a file.
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:231
bool empty() const
Definition: Identifier.h:61
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
Definition: Identifier.h:66
static Importer & Get()
Definition: Import.cpp:103
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:209
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:274
Provides a list of configurable commands for use with MacroCommands.
Entries::const_iterator ByCommandId(const CommandID &commandId) const
Entries::const_iterator end() const
Definition: BatchCommands.h:52
Entries::const_iterator ByTranslation(const wxString &translation) const
bool IsFixed(const wxString &name)
void AddToMacro(const CommandID &command, int before=-1)
wxString GetParams(int index)
void DeleteFromMacro(int index)
bool RenameMacro(const wxString &oldmacro, const wxString &newmacro)
CommandID GetCommand(int index)
static wxArrayString GetNames()
bool DeleteMacro(const wxString &name)
wxString WriteMacro(const wxString &macro, wxWindow *parent=nullptr)
bool ApplyMacro(const MacroCommandsCatalog &catalog, const wxString &filename={})
static wxString PromptForParamsFor(const CommandID &command, const wxString &params, wxWindow &parent)
bool AddMacro(const wxString &macro)
wxString ReadMacro(const wxString &macro, wxWindow *parent=nullptr)
void RestoreMacro(const wxString &name)
void PopulateList()
This clears and updates the contents of mList, the commands for the current macro.
TranslatableString WindowTitle() const
void OnDelete(wxCommandEvent &event)
void OnListSelected(wxListEvent &event)
An item in the macros list has been selected.
void OnShrink(wxCommandEvent &event)
void OnExport(wxCommandEvent &event)
wxButton * mRemove
void PopulateOrExchange(ShuttleGui &S)
Defines the dialog and does data exchange with it.
void OnRestore(wxCommandEvent &event)
Reset a built in macro.
void OnCommandActivated(wxListEvent &event)
AudacityProject & mProject
void OnAdd(wxCommandEvent &event)
void OnUp(wxCommandEvent &event)
void OnCancel(wxCommandEvent &event) override
void OnApplyToProject(wxCommandEvent &event) override
void OnMacroSelected(wxListEvent &event)
An item in the macros list has been selected.
void OnExpand(wxCommandEvent &event)
wxButton * mRestore
wxButton * mImport
void OnSave(wxCommandEvent &event)
void OnApplyToFiles(wxCommandEvent &event) override
void UpdateDisplay(bool bExpanded)
void UpdatePrefs() override
void OnMacrosBeginEdit(wxListEvent &event)
void OnSize(wxSizeEvent &event)
The window has been resized.
wxButton * mRename
wxButton * mExport
void OnMacrosEndEdit(wxListEvent &event)
void OnImport(wxCommandEvent &event)
MacrosWindow(wxWindow *parent, AudacityProject &project, bool bExpanded=true)
Constructor.
void OnDown(wxCommandEvent &event)
void OnEditCommandParams(wxCommandEvent &event)
void OnInsert(wxCommandEvent &event)
void OnRemove(wxCommandEvent &event)
void InsertCommandAt(int item)
void Populate()
Creates the dialog and its contents.
void AddItem(const CommandID &command, wxString const &params)
Add one item into mList.
void OnKeyDown(wxKeyEvent &event)
void OnOK(wxCommandEvent &event)
Send changed values back to Prefs, and update Audacity.
void OnRename(wxCommandEvent &event)
void RebuildMenuBar()
static MenuCreator & Get(AudacityProject &project)
Definition: MenuCreator.cpp:91
bool Import(const FilePath &fileName, bool addToHistory=true)
static ProjectFileManager & Get(AudacityProject &project)
static ProjectManager & Get(AudacityProject &project)
void ResetProjectToEmpty()
Generates classes whose instances register items at construction.
Definition: Registry.h:388
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
bool empty() const
Definition: Track.cpp:758
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
Holds a msgid for the translation catalog; may also bind format arguments.
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
void ZoomFitHorizontallyAndShowTrack(Track *pTrack)
Definition: Viewport.cpp:443
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:33
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
void SetTitle(const TranslatableString &title)
void SetLabel(const TranslatableString &title)
void SetName(const TranslatableString &title)
std::function< void()> Action
Definition: BasicUI.h:24
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1149
IMPORT_EXPORT_API ExportResult Show(ExportTask exportTask)
FILES_API FilePath FindDefaultPath(Operation op)
constexpr auto Section
Definition: MenuRegistry.h:436
constexpr auto Items
Definition: MenuRegistry.h:427
constexpr auto Command
Definition: MenuRegistry.h:456
constexpr auto Menu
Items will appear in a main toolbar menu or in a sub-menu.
Definition: MenuRegistry.h:445
std::unique_ptr< detail::IndirectItem< Item > > Indirect(const std::shared_ptr< Item > &ptr)
A convenience function.
Definition: Registry.h:175
void DoSelectAll(AudacityProject &project)
void OnRepeatLastTool(const CommandContext &context)
void OnApplyMacroDirectlyByName(const CommandContext &context, const MacroID &Name)
void OnApplyMacrosPalette(const CommandContext &context)
void OnManageMacros(const CommandContext &context)
void OnApplyMacroDirectly(const CommandContext &context)
AttachedWindows::RegisteredFactory sMacrosWindowKey
void PopulateMacrosMenu(MenuRegistry::MenuItems &items, CommandFlag flags)
const TranslatableString desc
Definition: ExportPCM.cpp:51
static CommandContext::TargetFactory::SubstituteInUnique< InteractiveOutputTargets > scope
Empty the clipboard at start of scope; restore its contents after.
Definition: Clipboard.h:70
auto push_back(Arg &&arg) -> std::enable_if_t< Traits< Base, Derived > ::template enables_item_type_v< Arg >, void >
Definition: Composite.h:105
Options && IsGlobal() &&
Definition: MenuRegistry.h:56
Options && AllowInMacros(int value=1) &&
Definition: MenuRegistry.h:69