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