Audacity 3.2.0
PluginMenus.cpp
Go to the documentation of this file.
1
2
3#include "../AudioIO.h"
4#include "../BatchProcessDialog.h"
5#include "../Benchmark.h"
6#include "../CommonCommandFlags.h"
7#include "../Journal.h"
8#include "../Menus.h"
9#include "PluginManager.h"
10#include "../PluginRegistrationDialog.h"
11#include "Prefs.h"
12#include "Project.h"
13#include "../ProjectSettings.h"
14#include "../ProjectWindow.h"
15#include "../ProjectWindows.h"
16#include "../ProjectSelectionManager.h"
17#include "../toolbars/ToolManager.h"
18#include "../Screenshot.h"
19#include "TempDirectory.h"
20#include "UndoManager.h"
21#include "../commands/CommandContext.h"
22#include "../commands/CommandManager.h"
23#include "../effects/EffectManager.h"
24#include "../effects/EffectUI.h"
25#include "../effects/RealtimeEffectManager.h"
26#include "../prefs/EffectsPrefs.h"
27#include "../prefs/PrefsDialog.h"
28#include "../widgets/AudacityMessageBox.h"
29
30#include <wx/log.h>
31
32// private helper classes and functions
33namespace {
34
35AttachedWindows::RegisteredFactory sMacrosWindowKey{
36 []( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
37 auto &window = ProjectWindow::Get( parent );
38 return safenew MacrosWindow(
39 &window, parent, true
40 );
41 }
42};
43
45 PluginManager &pm, wxWindow *parent)
46{
47 PluginRegistrationDialog dlg(parent);
48 return dlg.ShowModal() == wxID_OK;
49}
50
52{
53 auto &window = GetProjectFrame( project );
54 auto &pm = PluginManager::Get();
55 if (ShowManager(pm, &window))
57}
58
60{
61 return
62 std::make_pair( a->GetSymbol().Translation(), a->GetPath() ) <
63 std::make_pair( b->GetSymbol().Translation(), b->GetPath() );
64}
65
67 const PluginDescriptor *a, const PluginDescriptor *b)
68{
69 auto &em = EffectManager::Get();
70
71 auto akey = em.GetVendorName(a->GetID());
72 auto bkey = em.GetVendorName(b->GetID());
73
74 if (akey.empty())
75 akey = XO("Uncategorized");
76 if (bkey.empty())
77 bkey = XO("Uncategorized");
78
79 return
80 std::make_tuple(
81 akey.Translation(), a->GetSymbol().Translation(), a->GetPath() ) <
82 std::make_tuple(
83 bkey.Translation(), b->GetSymbol().Translation(), b->GetPath() );
84}
85
87 const PluginDescriptor *a, const PluginDescriptor *b)
88{
89 auto &em = EffectManager::Get();
90 auto akey = em.GetVendorName(a->GetID());
91 auto bkey = em.GetVendorName(b->GetID());
92
93 if (a->IsEffectDefault())
94 akey = {};
95 if (b->IsEffectDefault())
96 bkey = {};
97
98 return
99 std::make_tuple(
100 akey.Translation(), a->GetSymbol().Translation(), a->GetPath() ) <
101 std::make_tuple(
102 bkey.Translation(), b->GetSymbol().Translation(), b->GetPath() );
103}
104
106 const PluginDescriptor *a, const PluginDescriptor *b)
107{
108 auto &em = EffectManager::Get();
109 auto akey = em.GetEffectFamilyName(a->GetID());
110 auto bkey = em.GetEffectFamilyName(b->GetID());
111
112 if (akey.empty())
113 akey = XO("Uncategorized");
114 if (bkey.empty())
115 bkey = XO("Uncategorized");
116
117 if (a->IsEffectDefault())
118 akey = {};
119 if (b->IsEffectDefault())
120 bkey = {};
121
122 return
123 std::make_tuple(
124 akey.Translation(), a->GetSymbol().Translation(), a->GetPath() ) <
125 std::make_tuple(
126 bkey.Translation(), b->GetSymbol().Translation(), b->GetPath() );
127}
128
130{
131 auto &em = EffectManager::Get();
132 auto akey = em.GetEffectFamilyName(a->GetID());
133 auto bkey = em.GetEffectFamilyName(b->GetID());
134
135 if (akey.empty())
136 akey = XO("Uncategorized");
137 if (bkey.empty())
138 bkey = XO("Uncategorized");
139
140 return
141 std::make_tuple(
142 akey.Translation(), a->GetSymbol().Translation(), a->GetPath() ) <
143 std::make_tuple(
144 bkey.Translation(), b->GetSymbol().Translation(), b->GetPath() );
145}
146
147// Forward-declared function has its definition below with OnEffect in view
151 const PluginIDs & plugs,
152 const std::vector<CommandFlag> & flags,
153 bool isDefault);
154
157 std::vector<const PluginDescriptor*> & plugs,
158 CommandFlag batchflags,
159 CommandFlag realflags,
160 bool isDefault)
161{
162 size_t pluginCnt = plugs.size();
163
164 auto groupBy = EffectsGroupBy.Read();
165
166 bool grouped = false;
167 if (groupBy.StartsWith(wxT("groupby")))
168 {
169 grouped = true;
170 }
171
172 // Some weird special case stuff just for Noise Reduction so that there is
173 // more informative help
174 const auto getBatchFlags = [&]( const PluginDescriptor *plug ){
175 if ( plug->GetSymbol().Msgid() == XO( "Noise Reduction" ) )
176 return
177 ( batchflags | NoiseReductionTimeSelectedFlag() ) & ~TimeSelectedFlag();
178 return batchflags;
179 };
180
181 TranslatableStrings groupNames;
182 PluginIDs groupPlugs;
183 std::vector<CommandFlag> groupFlags;
184 if (grouped)
185 {
187 TranslatableString current;
188
189 for (size_t i = 0; i < pluginCnt; i++)
190 {
191 const PluginDescriptor *plug = plugs[i];
192
193 auto name = plug->GetSymbol().Msgid();
194
195 if (plug->IsEffectInteractive())
196 name += XO("...");
197
198 if (groupBy == wxT("groupby:publisher"))
199 {
200 current = EffectManager::Get().GetVendorName(plug->GetID());
201 if (current.empty())
202 {
203 current = XO("Unknown");
204 }
205 }
206 else if (groupBy == wxT("groupby:type"))
207 {
208 current = EffectManager::Get().GetEffectFamilyName(plug->GetID());
209 if (current.empty())
210 {
211 current = XO("Unknown");
212 }
213 }
214
215 if (current != last)
216 {
217 using namespace MenuTable;
218 BaseItemPtrs temp;
219 bool bInSubmenu = !last.empty() && (groupNames.size() > 1);
220
222 groupNames,
223 groupPlugs, groupFlags, isDefault);
224
225 table.push_back( MenuOrItems( wxEmptyString,
226 ( bInSubmenu ? last : TranslatableString{} ), std::move( temp )
227 ) );
228
229 groupNames.clear();
230 groupPlugs.clear();
231 groupFlags.clear();
232 last = current;
233 }
234
235 groupNames.push_back( name );
236 groupPlugs.push_back(plug->GetID());
237 groupFlags.push_back(
238 plug->IsEffectRealtime() ? realflags : getBatchFlags( plug ) );
239 }
240
241 if (groupNames.size() > 0)
242 {
243 using namespace MenuTable;
244 BaseItemPtrs temp;
245 bool bInSubmenu = groupNames.size() > 1;
246
248 groupNames, groupPlugs, groupFlags, isDefault);
249
250 table.push_back( MenuOrItems( wxEmptyString,
251 ( bInSubmenu ? current : TranslatableString{} ), std::move( temp )
252 ) );
253 }
254 }
255 else
256 {
257 for (size_t i = 0; i < pluginCnt; i++)
258 {
259 const PluginDescriptor *plug = plugs[i];
260
261 auto name = plug->GetSymbol().Msgid();
262
263 if (plug->IsEffectInteractive())
264 name += XO("...");
265
266 TranslatableString group;
267 if (groupBy == wxT("sortby:publisher:name"))
268 {
269 group = EffectManager::Get().GetVendorName(plug->GetID());
270 }
271 else if (groupBy == wxT("sortby:type:name"))
272 {
274 }
275
276 if (plug->IsEffectDefault())
277 {
278 group = {};
279 }
280
281 groupNames.push_back(
282 group.empty()
283 ? name
284 : XO("%s: %s").Format( group, name )
285 );
286
287 groupPlugs.push_back(plug->GetID());
288 groupFlags.push_back(
289 plug->IsEffectRealtime() ? realflags : getBatchFlags( plug ) );
290 }
291
292 if (groupNames.size() > 0)
293 {
295 table, groupNames, groupPlugs, groupFlags, isDefault);
296 }
297
298 }
299
300 return;
301}
302
307 EffectType type,
308 CommandFlag batchflags,
309 CommandFlag realflags)
310{
313
314 std::vector<const PluginDescriptor*> defplugs;
315 std::vector<const PluginDescriptor*> optplugs;
316
318 for (auto &plugin : pm.EffectsOfType(type)) {
319 auto plug = &plugin;
320 if( pm.IsPluginLoaded(plug->GetID()) && em.IsHidden(plug->GetID()) )
321 continue;
322 if ( !plug->IsEnabled() ){
323 ;// don't add to menus!
324 }
325 else if (plug->IsEffectDefault()
326#ifdef EXPERIMENTAL_DA
327 // Move Nyquist prompt into nyquist group.
328 && (plug->GetSymbol() !=
329 ComponentInterfaceSymbol("Nyquist Effects Prompt"))
330 && (plug->GetSymbol() != ComponentInterfaceSymbol("Nyquist Tools Prompt"))
331 && (plug->GetSymbol() != ComponentInterfaceSymbol(NYQUIST_PROMPT_ID))
332#endif
333 )
334 defplugs.push_back(plug);
335 else
336 optplugs.push_back(plug);
337 }
338
339 wxString groupby = EffectsGroupBy.Read();
340
341 using Comparator = bool(*)(const PluginDescriptor*, const PluginDescriptor*);
342 Comparator comp1, comp2;
343 if (groupby == wxT("sortby:name"))
344 comp1 = comp2 = CompareEffectsByName;
345 else if (groupby == wxT("sortby:publisher:name"))
347 else if (groupby == wxT("sortby:type:name"))
349 else if (groupby == wxT("groupby:publisher"))
350 comp1 = comp2 = CompareEffectsByPublisher;
351 else if (groupby == wxT("groupby:type"))
352 comp1 = comp2 = CompareEffectsByType;
353 else // name
354 comp1 = comp2 = CompareEffectsByName;
355
356 std::sort( defplugs.begin(), defplugs.end(), comp1 );
357 std::sort( optplugs.begin(), optplugs.end(), comp2 );
358
360 AddEffectMenuItems( section1, defplugs, batchflags, realflags, true );
361
363 AddEffectMenuItems( section2, optplugs, batchflags, realflags, false );
364
365 bool section = !section1.empty() && !section2.empty();
366 result.push_back( MenuTable::Items( "", std::move( section1 ) ) );
367 if ( section )
368 result.push_back( MenuTable::Section( "", std::move( section2 ) ) );
369 else
370 result.push_back( MenuTable::Items( "", std::move( section2 ) ) );
371
372 return result;
373}
374
375// Forward-declared function has its definition below with OnApplyMacroDirectly
376// in view
378
379}
380
381namespace PluginActions {
382
383// Menu handler functions
384
386
387void OnResetConfig(const CommandContext &context)
388{
389 auto &project = context.project;
390 auto &menuManager = MenuManager::Get(project);
391 menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypenone;
392 menuManager.mLastToolRegistration = MenuCreator::repeattypenone;
393 menuManager.mLastGenerator = "";
394 menuManager.mLastEffect = "";
395 menuManager.mLastAnalyzer = "";
396 menuManager.mLastTool = "";
397
399
400 // Directory will be reset on next restart.
401 FileNames::UpdateDefaultPath(FileNames::Operation::Temp, TempDirectory::DefaultTempDir());
402
403 // There are many more things we could reset here.
404 // Beeds discussion as to which make sense to.
405 // Maybe in future versions?
406 // - Reset Effects
407 // - Reset Recording and Playback volumes
408 // - Reset Selection formats (and for spectral too)
409 // - Reset Play-at-speed speed to x1
410 // - Stop playback/recording and unapply pause.
411 // - Set Zoom sensibly.
412 gPrefs->Write("/GUI/SyncLockTracks", 0);
413 gPrefs->Write("/AudioIO/SoundActivatedRecord", 0);
414 gPrefs->Write("/SelectionToolbarMode", 0);
415 gPrefs->Flush();
416 DoReloadPreferences(project);
417
420
421 // These are necessary to preserve the newly correctly laid out toolbars.
422 // In particular the Device Toolbar ends up short on next restart,
423 // if they are left out.
424 gPrefs->Write(wxT("/PrefsVersion"), wxString(wxT(AUDACITY_PREFS_VERSION_STRING)));
425
426 // write out the version numbers to the prefs file for future checking
427 gPrefs->Write(wxT("/Version/Major"), AUDACITY_VERSION);
428 gPrefs->Write(wxT("/Version/Minor"), AUDACITY_RELEASE);
429 gPrefs->Write(wxT("/Version/Micro"), AUDACITY_REVISION);
430
431 gPrefs->Flush();
432
434 .AS_SetSnapTo(gPrefs->ReadLong("/SnapTo", SNAP_OFF));
436 .AS_SetRate(gPrefs->ReadDouble("/DefaultProjectSampleRate", 44100.0));
437}
438
440{
441 auto &project = context.project;
442 DoManagePluginsMenu(project);
443}
444
445void OnEffect(const CommandContext &context)
446{
447 // using GET to interpret parameter as a PluginID
448 EffectUI::DoEffect(context.parameter.GET(), context, 0);
449}
450
451void OnManageEffects(const CommandContext &context)
452{
453 auto &project = context.project;
454 DoManagePluginsMenu(project);
455}
456
457void OnAnalyzer2(wxCommandEvent& evt) { return; }
458
460{
461 auto& menuManager = MenuManager::Get(context.project);
462 auto lastEffect = menuManager.mLastGenerator;
463 if (!lastEffect.empty())
464 {
466 lastEffect, context, menuManager.mRepeatGeneratorFlags | EffectManager::kRepeatGen);
467 }
468}
469
471{
472 auto& menuManager = MenuManager::Get(context.project);
473 auto lastEffect = menuManager.mLastEffect;
474 if (!lastEffect.empty())
475 {
477 lastEffect, context, menuManager.mRepeatEffectFlags);
478 }
479}
480
482{
483 auto& menuManager = MenuManager::Get(context.project);
484 switch (menuManager.mLastAnalyzerRegistration) {
486 {
487 auto lastEffect = menuManager.mLastAnalyzer;
488 if (!lastEffect.empty())
489 {
491 lastEffect, context, menuManager.mRepeatAnalyzerFlags);
492 }
493 }
494 break;
497 menuManager.mLastAnalyzerRegisteredId);
498 break;
499 }
500}
501
503{
504 auto& menuManager = MenuManager::Get(context.project);
505 switch (menuManager.mLastToolRegistration) {
507 {
508 auto lastEffect = menuManager.mLastTool;
509 if (!lastEffect.empty())
510 {
512 lastEffect, context, menuManager.mRepeatToolFlags);
513 }
514 }
515 break;
518 menuManager.mLastToolRegisteredId);
519 break;
521 OnApplyMacroDirectlyByName(context, menuManager.mLastTool);
522 break;
523 }
524}
525
526
528{
529 auto &project = context.project;
530 DoManagePluginsMenu(project);
531}
532
533void OnManageTools(const CommandContext &context )
534{
535 auto &project = context.project;
536 DoManagePluginsMenu(project);
537}
538
539void OnManageMacros(const CommandContext &context )
540{
541 auto &project = context.project;
542 CommandManager::Get(project).RegisterLastTool(context); //Register Macros as Last Tool
543 auto macrosWindow = &GetAttachedWindows(project)
544 .AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey );
545 if (macrosWindow) {
546 macrosWindow->Show();
547 macrosWindow->Raise();
548 macrosWindow->UpdateDisplay( true );
549 }
550}
551
553{
554 auto &project = context.project;
555 CommandManager::Get(project).RegisterLastTool(context); //Register Palette as Last Tool
556 auto macrosWindow = &GetAttachedWindows(project)
557 .AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey );
558 if (macrosWindow) {
559 macrosWindow->Show();
560 macrosWindow->Raise();
561 macrosWindow->UpdateDisplay( false );
562 }
563}
564
565void OnScreenshot(const CommandContext &context )
566{
567 CommandManager::Get(context.project).RegisterLastTool(context); //Register Screenshot as Last Tool
569}
570
571void OnBenchmark(const CommandContext &context)
572{
573 auto &project = context.project;
574 CommandManager::Get(project).RegisterLastTool(context); //Register Run Benchmark as Last Tool
575 auto &window = GetProjectFrame( project );
576 ::RunBenchmark( &window, project);
577}
578
580{
581 auto &project = context.project;
582 auto &commandManager = CommandManager::Get( project );
583
584 auto gAudioIO = AudioIO::Get();
585 bool &setting = gAudioIO->mSimulateRecordingErrors;
586 commandManager.Check(wxT("SimulateRecordingErrors"), !setting);
587 setting = !setting;
588}
589
591{
592 auto &project = context.project;
593 auto &commandManager = CommandManager::Get( project );
594
595 auto gAudioIO = AudioIO::Get();
596 auto &setting = gAudioIO->mDetectUpstreamDropouts;
597 auto oldValue = setting.load(std::memory_order_relaxed);
598 commandManager.Check(wxT("DetectUpstreamDropouts"), !oldValue);
599 setting.store(!oldValue, std::memory_order_relaxed);
600}
601
603{
604 auto OnMessage =
605 /* i18n-hint a "journal" is a text file that records
606 the user's interactions with the application */
607 XO("A journal will be recorded after Audacity restarts.");
608 auto OffMessage =
609 /* i18n-hint a "journal" is a text file that records
610 the user's interactions with the application */
611 XO("No journal will be recorded after Audacity restarts.");
612
613 using namespace Journal;
614 bool enabled = RecordEnabled();
615 if ( SetRecordEnabled(!enabled) )
616 enabled = !enabled;
617 if ( enabled )
618 AudacityMessageBox( OnMessage );
619 else
620 AudacityMessageBox( OffMessage );
621}
622
624{
625 const MacroID& Name = context.parameter.GET();
626 OnApplyMacroDirectlyByName(context, Name);
627}
628void OnApplyMacroDirectlyByName(const CommandContext& context, const MacroID& Name)
629{
630 auto &project = context.project;
631 auto &window = ProjectWindow::Get( project );
632 //wxLogDebug( "Macro was: %s", context.parameter);
633 ApplyMacroDialog dlg( &window, project );
634 //const auto &Name = context.parameter;
635
636// We used numbers previously, but macros could get renumbered, making
637// macros containing macros unpredictable.
638#ifdef MACROS_BY_NUMBERS
639 long item=0;
640 // Take last three letters (of e.g. Macro007) and convert to a number.
641 Name.Mid( Name.length() - 3 ).ToLong( &item, 10 );
642 dlg.ApplyMacroToProject( item, false );
643#else
644 dlg.ApplyMacroToProject( Name, false );
645#endif
646 /* i18n-hint: %s will be the name of the macro which will be
647 * repeated if this menu item is chosen */
649
652 auto shortDesc = em.GetCommandName(Name);
653 auto& undoManager = UndoManager::Get(project);
654 auto& commandManager = CommandManager::Get(project);
655 int cur = undoManager.GetCurrentState();
656 if (undoManager.UndoAvailable()) {
657 undoManager.GetShortDescription(cur, &desc);
658 commandManager.Modify(wxT("RepeatLastTool"), XXO("&Repeat %s")
659 .Format(desc));
660 auto& menuManager = MenuManager::Get(project);
661 menuManager.mLastTool = Name;
662 menuManager.mLastToolRegistration = MenuCreator::repeattypeapplymacro;
663 }
664
665}
666
668{
669 // using GET in a log message for devs' eyes only
670 wxLogDebug( "Command was: %s", ctx.parameter.GET());
671 // Not configured, so prompt user.
673 EffectManager::Get().GetEffectByIdentifier(ctx.parameter),
675}
676
677}; // struct Handler
678
679} // namespace
680
682 // Handler is not stateful. Doesn't need a factory registered with
683 // AudacityProject.
684 static PluginActions::Handler instance;
685 return instance;
686};
687
688// Menu definitions? ...
689
690#define FN(X) (& PluginActions::Handler :: X)
691
692// ... buf first some more helper definitions, which use FN
693namespace {
694
698 const PluginIDs & plugs,
699 const std::vector<CommandFlag> & flags,
700 bool isDefault)
701{
702 const int namesCnt = (int) names.size();
703 int perGroup;
704
705#if defined(__WXGTK__)
706 gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 15);
707#else
708 gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 0);
709#endif
710
711 int groupCnt = namesCnt;
712 for (int i = 0; i < namesCnt; i++)
713 {
714 // compare full translations not msgids!
715 while (i + 1 < namesCnt && names[i].Translation() == names[i + 1].Translation())
716 {
717 i++;
718 groupCnt--;
719 }
720 }
721
722 // The "default" effects shouldn't be broken into subgroups
723 if (namesCnt > 0 && isDefault)
724 {
725 perGroup = 0;
726 }
727
728 int max = perGroup;
729 int items = perGroup;
730
731 if (max > groupCnt)
732 {
733 max = 0;
734 }
735
736 using namespace MenuTable;
737 // This finder scope may be redundant, but harmless
739 auto pTable = &table;
740 BaseItemPtrs temp1;
741
742 int groupNdx = 0;
743 for (int i = 0; i < namesCnt; i++)
744 {
745 if (max > 0 && items == max)
746 {
747 // start collecting items for the next submenu
748 pTable = &temp1;
749 }
750
751 // compare full translations not msgids!
752 if (i + 1 < namesCnt && names[i].Translation() == names[i + 1].Translation())
753 {
754 // collect a sub-menu for like-named items
755 const auto name = names[i];
756 const auto translation = name.Translation();
757 BaseItemPtrs temp2;
758 // compare full translations not msgids!
759 while (i < namesCnt && names[i].Translation() == translation)
760 {
761 const PluginDescriptor *plug =
762 PluginManager::Get().GetPlugin(plugs[i]);
763 wxString item = plug->GetPath();
764 if( plug->GetPluginType() == PluginTypeEffect )
765 temp2.push_back( Command( item,
766 Verbatim( item ),
767 FN(OnEffect),
768 flags[i],
770 .IsEffect()
771 .AllowInMacros()
772 .Parameter( plugs[i] ) ) );
773
774 i++;
775 }
776 pTable->push_back( Menu( wxEmptyString, name, std::move( temp2 ) ) );
777 i--;
778 }
779 else
780 {
781 // collect one item
782 const PluginDescriptor *plug =
783 PluginManager::Get().GetPlugin(plugs[i]);
784 if( plug->GetPluginType() == PluginTypeEffect )
785 pTable->push_back( Command(
786 // Call Debug() not MSGID() so that any concatenated "..." is
787 // included in the identifier, preserving old behavior, and
788 // avoiding the collision of the "Silence" command and the
789 // "Silence..." generator
790 names[i].Debug(), // names[i].MSGID(),
791 names[i],
792 FN(OnEffect),
793 flags[i],
795 .IsEffect()
796 .AllowInMacros()
797 .Parameter( plugs[i] ) ) );
798 }
799
800 if (max > 0)
801 {
802 items--;
803 if (items == 0 || i + 1 == namesCnt)
804 {
805 int end = groupNdx + max;
806 if (end + 1 > groupCnt)
807 {
808 end = groupCnt;
809 }
810 // Done collecting
811 table.push_back( Menu( wxEmptyString,
812 XXO("Plug-in %d to %d").Format( groupNdx + 1, end ),
813 std::move( temp1 )
814 ) );
815 items = max;
816 pTable = &table;
817 groupNdx += max;
818 }
819 }
820 }
821
822 return;
823}
824
826{
828 auto names = MacroCommands::GetNames(); // these names come from filenames
829 int i;
830
831 // This finder scope may be redundant, but harmless
833 for (i = 0; i < (int)names.size(); i++) {
835 result.push_back( MenuTable::Command( MacroID,
836 Verbatim( names[i] ), // file name verbatim
837 FN(OnApplyMacroDirectly),
838 flags,
840 ) );
841 }
842
843 return result;
844}
845
846}
847
848// Menu definitions
849
850// Under /MenuBar
851namespace {
852using namespace MenuTable;
853
856 [](const AudacityProject &project){
857 return !MenuManager::Get( project ).mLastGenerator.empty();
858 }
859 }; return flag; }
860
862{
863 // All of this is a bit hacky until we can get more things connected into
864 // the plugin manager...sorry! :-(
865
867
868 static BaseItemSharedPtr menu{
870 Menu( wxT("Generate"), XXO("&Generate"),
871 Section( "Manage",
872 Command( wxT("ManageGenerators"), XXO("Add / Remove Plug-ins..."),
873 FN(OnManageGenerators), AudioIONotBusyFlag() )
874 ),
875
876 Section("RepeatLast",
877 // Delayed evaluation:
878 [](AudacityProject &project)
879 {
880 const auto &lastGenerator = MenuManager::Get(project).mLastGenerator;
881 TranslatableString buildMenuLabel;
882 if (!lastGenerator.empty())
883 buildMenuLabel = XO("Repeat %s")
884 .Format(EffectManager::Get().GetCommandName(lastGenerator));
885 else
886 buildMenuLabel = XO("Repeat Last Generator");
887
888 return Command(wxT("RepeatLastGenerator"), buildMenuLabel,
889 FN(OnRepeatLastGenerator),
892 Options{}.IsGlobal(), findCommandHandler);
893 }
894 ),
895
896 Section( "Generators",
897 // Delayed evaluation:
898 [](AudacityProject &)
899 { return Items( wxEmptyString, PopulateEffectsMenu(
903 ); }
904 )
905 ) ) };
906 return menu;
907}
908
909static const ReservedCommandFlag
911 [](const AudacityProject &project){
912 return !RealtimeEffectManager::Get(project).IsActive();
913 }
914}; return flag; } //lll
915
917 wxT(""),
919};
920
923 [](const AudacityProject &project) {
924 return !MenuManager::Get(project).mLastEffect.empty();
925 }
926 }; return flag;
927}
928
930{
931 // All of this is a bit hacky until we can get more things connected into
932 // the plugin manager...sorry! :-(
933
934 static BaseItemSharedPtr menu{
936 Menu( wxT("Effect"), XXO("Effe&ct"),
937 Section( "Manage",
938 Command( wxT("ManageEffects"), XXO("Add / Remove Plug-ins..."),
939 FN(OnManageEffects), AudioIONotBusyFlag() )
940 ),
941
942 Section( "RepeatLast",
943 // Delayed evaluation:
944 [](AudacityProject &project)
945 {
946 const auto &lastEffect = MenuManager::Get(project).mLastEffect;
947 TranslatableString buildMenuLabel;
948 if (!lastEffect.empty())
949 buildMenuLabel = XO("Repeat %s")
950 .Format( EffectManager::Get().GetCommandName(lastEffect) );
951 else
952 buildMenuLabel = XO("Repeat Last Effect");
953
954 return Command( wxT("RepeatLastEffect"), buildMenuLabel,
955 FN(OnRepeatLastEffect),
958 wxT("Ctrl+R"), findCommandHandler );
959 }
960 ),
961
962 Section( "Effects",
963 // Delayed evaluation:
964 [](AudacityProject &)
965 { return Items( wxEmptyString, PopulateEffectsMenu(
969 ); }
970 )
971 ) ) };
972 return menu;
973}
974
976 wxT(""),
977 Shared( EffectMenu() )
978};
979
982 [](const AudacityProject &project) {
984 return !MenuManager::Get(project).mLastAnalyzer.empty();
985 }
986 }; return flag;
987}
988
990{
991 // All of this is a bit hacky until we can get more things connected into
992 // the plugin manager...sorry! :-(
993
995
996 static BaseItemSharedPtr menu{
998 Menu( wxT("Analyze"), XXO("&Analyze"),
999 Section( "Manage",
1000 Command( wxT("ManageAnalyzers"), XXO("Add / Remove Plug-ins..."),
1001 FN(OnManageAnalyzers), AudioIONotBusyFlag() )
1002 ),
1003
1004 Section("RepeatLast",
1005 // Delayed evaluation:
1006 [](AudacityProject &project)
1007 {
1008 const auto &lastAnalyzer = MenuManager::Get(project).mLastAnalyzer;
1009 TranslatableString buildMenuLabel;
1010 if (!lastAnalyzer.empty())
1011 buildMenuLabel = XO("Repeat %s")
1012 .Format(EffectManager::Get().GetCommandName(lastAnalyzer));
1013 else
1014 buildMenuLabel = XO("Repeat Last Analyzer");
1015
1016 return Command(wxT("RepeatLastAnalyzer"), buildMenuLabel,
1017 FN(OnRepeatLastAnalyzer),
1020 Options{}.IsGlobal(), findCommandHandler);
1021 }
1022 ),
1023
1024 Section( "Analyzers",
1025 Items( "Windows" ),
1026
1027 // Delayed evaluation:
1028 [](AudacityProject&)
1029 { return Items( wxEmptyString, PopulateEffectsMenu(
1033 ); }
1034 )
1035 ) ) };
1036 return menu;
1037}
1038
1040 wxT(""),
1041 Shared( AnalyzeMenu() )
1042};
1043
1046 [](const AudacityProject &project) {
1047 auto& menuManager = MenuManager::Get(project);
1048 if (menuManager.mLastToolRegistration == MenuCreator::repeattypeunique) return true;
1049 return !menuManager.mLastTool.empty();
1050 }
1051 }; return flag;
1052}
1053
1055{
1057
1058 static BaseItemSharedPtr menu{
1060 Menu( wxT("Tools"), XXO("T&ools"),
1061 Section( "Manage",
1062 Command( wxT("ManageTools"), XXO("Add / Remove Plug-ins..."),
1063 FN(OnManageTools), AudioIONotBusyFlag() ),
1064
1065 //Separator(),
1066
1067 Section( "RepeatLast",
1068 // Delayed evaluation:
1069 [](AudacityProject &project)
1070 {
1071 const auto &lastTool = MenuManager::Get(project).mLastTool;
1072 TranslatableString buildMenuLabel;
1073 if (!lastTool.empty())
1074 buildMenuLabel = XO("Repeat %s")
1075 .Format( EffectManager::Get().GetCommandName(lastTool) );
1076 else
1077 buildMenuLabel = XO("Repeat Last Tool");
1078
1079 return Command( wxT("RepeatLastTool"), buildMenuLabel,
1080 FN(OnRepeatLastTool),
1083 Options{}.IsGlobal(), findCommandHandler );
1084 }
1085 ),
1086
1087 Command( wxT("ManageMacros"), XXO("&Macros..."),
1088 FN(OnManageMacros), AudioIONotBusyFlag() ),
1089
1090 Menu( wxT("Macros"), XXO("&Apply Macro"),
1091 // Palette has no access key to ensure first letter navigation of
1092 // sub menu
1093 Section( "",
1094 Command( wxT("ApplyMacrosPalette"), XXO("Palette..."),
1095 FN(OnApplyMacrosPalette), AudioIONotBusyFlag() )
1096 ),
1097
1098 Section( "",
1099 // Delayed evaluation:
1100 [](AudacityProject&)
1101 { return Items( wxEmptyString, PopulateMacrosMenu( AudioIONotBusyFlag() ) ); }
1102 )
1103 )
1104 ),
1105
1106 Section( "Other",
1107 Command( wxT("ConfigReset"), XXO("Reset &Configuration"),
1108 FN(OnResetConfig),
1110
1111 Command( wxT("FancyScreenshot"), XXO("&Screenshot..."),
1112 FN(OnScreenshot), AudioIONotBusyFlag() ),
1113
1114 // PRL: team consensus for 2.2.0 was, we let end users have this diagnostic,
1115 // as they used to in 1.3.x
1116 //#ifdef IS_ALPHA
1117 // TODO: What should we do here? Make benchmark a plug-in?
1118 // Easy enough to do. We'd call it mod-self-test.
1119 Command( wxT("Benchmark"), XXO("&Run Benchmark..."),
1120 FN(OnBenchmark), AudioIONotBusyFlag() )
1121 //#endif
1122 ),
1123
1124 Section( "Tools",
1125 // Delayed evaluation:
1126 [](AudacityProject&)
1127 { return Items( wxEmptyString, PopulateEffectsMenu(
1131 ); }
1132 )
1133
1134#ifdef IS_ALPHA
1135 ,
1136 Section( "",
1137 Command( wxT("SimulateRecordingErrors"),
1138 XXO("Simulate Recording Errors"),
1139 FN(OnSimulateRecordingErrors),
1141 Options{}.CheckTest(
1142 [](AudacityProject&){
1143 return AudioIO::Get()->mSimulateRecordingErrors; } ) ),
1144 Command( wxT("DetectUpstreamDropouts"),
1145 XXO("Detect Upstream Dropouts"),
1146 FN(OnDetectUpstreamDropouts),
1148 Options{}.CheckTest(
1149 [](AudacityProject&){
1151 .load(std::memory_order_relaxed); } ) )
1152 )
1153#endif
1154
1155#if defined(IS_ALPHA) || defined(END_USER_JOURNALLING)
1156 ,
1157 Section( "",
1158 Command( wxT("WriteJournal"),
1159 /* i18n-hint a "journal" is a text file that records
1160 the user's interactions with the application */
1161 XXO("Write Journal"),
1162 FN(OnWriteJournal),
1164 Options{}.CheckTest( [](AudacityProject&){
1165 return Journal::RecordEnabled(); } ) )
1166 )
1167#endif
1168
1169 ) ) };
1170 return menu;
1171}
1172
1174 wxT(""),
1175 Shared( ToolsMenu() )
1176};
1177
1179{
1180 // These are the more useful to VI user Scriptables.
1181 static BaseItemSharedPtr menu{
1183 // i18n-hint: Scriptables are commands normally used from Python, Perl etc.
1184 Menu( wxT("Scriptables1"), XXO("Script&ables I"),
1185 // Note that the PLUGIN_SYMBOL must have a space between words,
1186 // whereas the short-form used here must not.
1187 // (So if you did write "CompareAudio" for the PLUGIN_SYMBOL name, then
1188 // you would have to use "Compareaudio" here.)
1189 Command( wxT("SelectTime"), XXO("Select Time..."), FN(OnAudacityCommand),
1191 Command( wxT("SelectFrequencies"), XXO("Select Frequencies..."),
1192 FN(OnAudacityCommand),
1194 Command( wxT("SelectTracks"), XXO("Select Tracks..."),
1195 FN(OnAudacityCommand),
1197 Command( wxT("SetTrackStatus"), XXO("Set Track Status..."),
1198 FN(OnAudacityCommand),
1200 Command( wxT("SetTrackAudio"), XXO("Set Track Audio..."),
1201 FN(OnAudacityCommand),
1203 Command( wxT("SetTrackVisuals"), XXO("Set Track Visuals..."),
1204 FN(OnAudacityCommand),
1206 Command( wxT("GetPreference"), XXO("Get Preference..."),
1207 FN(OnAudacityCommand),
1209 Command( wxT("SetPreference"), XXO("Set Preference..."),
1210 FN(OnAudacityCommand),
1212 Command( wxT("SetClip"), XXO("Set Clip..."), FN(OnAudacityCommand),
1214 Command( wxT("SetEnvelope"), XXO("Set Envelope..."),
1215 FN(OnAudacityCommand),
1217 Command( wxT("SetLabel"), XXO("Set Label..."), FN(OnAudacityCommand),
1219 Command( wxT("SetProject"), XXO("Set Project..."), FN(OnAudacityCommand),
1221 ) ) };
1222 return menu;
1223}
1224
1226 wxT("Optional/Extra/Part2"),
1228};
1229
1231{
1232 // Less useful to VI users.
1233 static BaseItemSharedPtr menu{
1235 // i18n-hint: Scriptables are commands normally used from Python, Perl etc.
1236 Menu( wxT("Scriptables2"), XXO("Scripta&bles II"),
1237 Command( wxT("Select"), XXO("Select..."), FN(OnAudacityCommand),
1239 Command( wxT("SetTrack"), XXO("Set Track..."), FN(OnAudacityCommand),
1241 Command( wxT("GetInfo"), XXO("Get Info..."), FN(OnAudacityCommand),
1243 Command( wxT("Message"), XXO("Message..."), FN(OnAudacityCommand),
1245 Command( wxT("Help"), XXO("Help..."), FN(OnAudacityCommand),
1247 Command( wxT("Import2"), XXO("Import..."), FN(OnAudacityCommand),
1249 Command( wxT("Export2"), XXO("Export..."), FN(OnAudacityCommand),
1251 Command( wxT("OpenProject2"), XXO("Open Project..."),
1252 FN(OnAudacityCommand),
1254 Command( wxT("SaveProject2"), XXO("Save Project..."),
1255 FN(OnAudacityCommand),
1257 Command( wxT("Drag"), XXO("Move Mouse..."), FN(OnAudacityCommand),
1259 Command( wxT("CompareAudio"), XXO("Compare Audio..."),
1260 FN(OnAudacityCommand),
1262 // i18n-hint: Screenshot in the help menu has a much bigger dialog.
1263 Command( wxT("Screenshot"), XXO("Screenshot (short format)..."),
1264 FN(OnAudacityCommand),
1266 ) ) };
1267 return menu;
1268}
1269
1271 wxT("Optional/Extra/Part2"),
1273};
1274
1275}
1276
1277#undef FN
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
void RunBenchmark(wxWindow *parent, AudacityProject &project)
Definition: Benchmark.cpp:95
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:31
wxEvtHandler CommandHandlerObject
const ReservedCommandFlag & NoiseReductionTimeSelectedFlag()
const ReservedCommandFlag & AudioIONotBusyFlag()
const ReservedCommandFlag & TimeSelectedFlag()
const ReservedCommandFlag & WaveTracksSelectedFlag()
static TransactionScope::Factory::Scope scope
const TranslatableString name
Definition: Distortion.cpp:82
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
ChoiceSetting EffectsGroupBy
const TranslatableString desc
Definition: ExportPCM.cpp:58
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define safenew
Definition: MemoryX.h:10
wxString MacroID
Definition: Menus.h:33
wxArrayString PluginIDs
Definition: Menus.h:34
@ PluginTypeEffect
#define NYQUIST_PROMPT_ID
static CommandHandlerObject & findCommandHandler(AudacityProject &)
#define FN(X)
FileConfig * gPrefs
Definition: Prefs.cpp:71
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
Definition: Prefs.cpp:208
#define AUDACITY_PREFS_VERSION_STRING
Definition: Prefs.h:38
void DoReloadPreferences(AudacityProject &project)
@ SNAP_OFF
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)
void OpenScreenshotTools(AudacityProject &project)
Definition: Screenshot.cpp:135
static TranslatableStrings names
Definition: TagsEditor.cpp:151
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static std::once_flag flag
Shows progress in executing commands in MacroCommands.
void ApplyMacroToProject(int iMacro, bool bHasGui=true)
static CommandID MacroIdOfName(const wxString &MacroName)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
static AudioIO * Get()
Definition: AudioIO.cpp:140
bool mSimulateRecordingErrors
Definition: AudioIO.h:379
std::atomic< bool > mDetectUpstreamDropouts
Definition: AudioIO.h:383
wxString Read() const
Definition: Prefs.cpp:327
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
CommandParameter parameter
AudacityProject & project
void RegisterLastTool(const CommandContext &context)
void DoRepeatProcess(const CommandContext &context, int)
static CommandManager & Get(AudacityProject &project)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const TranslatableString & Msgid() const
const wxString Translation() const
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:48
static EffectManager & Get()
TranslatableString GetCommandName(const PluginID &ID)
TranslatableString GetVendorName(const PluginID &ID)
TranslatableString GetEffectFamilyName(const PluginID &ID)
bool IsHidden(const PluginID &ID)
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
Abstract base class used in importing a file.
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 wxArrayString GetNames()
static bool DoAudacityCommand(const PluginID &ID, const CommandContext &context, unsigned flags)
void UpdateDisplay(bool bExpanded)
static void RebuildAllMenuBars()
Definition: Menus.cpp:687
PluginID mLastAnalyzer
Definition: Menus.h:54
int mLastAnalyzerRegistration
Definition: Menus.h:55
PluginID mLastGenerator
Definition: Menus.h:52
PluginID mLastTool
Definition: Menus.h:57
@ repeattypeplugin
Definition: Menus.h:62
@ repeattypeapplymacro
Definition: Menus.h:64
@ repeattypenone
Definition: Menus.h:61
@ repeattypeunique
Definition: Menus.h:63
PluginID mLastEffect
Definition: Menus.h:53
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:71
static void ModifyUndoMenuItems(AudacityProject &project)
Definition: Menus.cpp:444
const ComponentInterfaceSymbol & GetSymbol() const
bool IsEffectRealtime() const
PluginType GetPluginType() const
bool IsEffectDefault() const
bool IsEffectInteractive() const
const wxString & GetID() const
const PluginPath & GetPath() const
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
Definition: PluginManager.h:41
Range EffectsOfType(EffectType type)
bool IsPluginLoaded(const wxString &ID) const
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
void AS_SetSnapTo(int snap) override
static ProjectSelectionManager & Get(AudacityProject &project)
void AS_SetRate(double rate) override
static ProjectWindow & Get(AudacityProject &project)
static void OnResetWindow(const CommandContext &context)
static RealtimeEffectManager & Get(AudacityProject &project)
bool IsActive() const noexcept
static void OnResetToolBars(const CommandContext &context)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:67
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1275
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
Facilities for recording and playback of sequences of user interaction.
bool RecordEnabled()
Definition: Journal.cpp:119
bool SetRecordEnabled(bool value)
Definition: Journal.cpp:124
std::unique_ptr< MenuItem > Menu(const Identifier &internalName, const TranslatableString &title, Args &&... args)
std::unique_ptr< MenuPart > Section(const Identifier &internalName, Args &&... args)
std::unique_ptr< MenuItems > Items(const Identifier &internalName, Args &&... args)
std::unique_ptr< CommandItem > Command(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const CommandManager::Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
BaseItemPtr MenuOrItems(const Identifier &internalName, const TranslatableString &title, Args &&... args)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
std::vector< BaseItemPtr > BaseItemPtrs
Definition: Registry.h:73
std::shared_ptr< BaseItem > BaseItemSharedPtr
Definition: Registry.h:72
FILES_API const FilePath & DefaultTempDir()
std::vector< CommandFlagOptions > & Options()
Definition: Menus.cpp:535
MenuTable::BaseItemPtrs PopulateEffectsMenu(EffectType type, CommandFlag batchflags, CommandFlag realflags)
const ReservedCommandFlag & HasLastToolFlag()
const ReservedCommandFlag & HasLastEffectFlag()
bool CompareEffectsByType(const PluginDescriptor *a, const PluginDescriptor *b)
void AddEffectMenuItems(MenuTable::BaseItemPtrs &table, std::vector< const PluginDescriptor * > &plugs, CommandFlag batchflags, CommandFlag realflags, bool isDefault)
bool CompareEffectsByName(const PluginDescriptor *a, const PluginDescriptor *b)
Definition: PluginMenus.cpp:59
AttachedWindows::RegisteredFactory sMacrosWindowKey
Definition: PluginMenus.cpp:35
const ReservedCommandFlag & HasLastAnalyzerFlag()
bool CompareEffectsByPublisherAndName(const PluginDescriptor *a, const PluginDescriptor *b)
Definition: PluginMenus.cpp:86
void DoManagePluginsMenu(AudacityProject &project)
Definition: PluginMenus.cpp:51
bool ShowManager(PluginManager &pm, wxWindow *parent)
Definition: PluginMenus.cpp:44
bool CompareEffectsByTypeAndName(const PluginDescriptor *a, const PluginDescriptor *b)
static const ReservedCommandFlag & IsRealtimeNotActiveFlag()
bool CompareEffectsByPublisher(const PluginDescriptor *a, const PluginDescriptor *b)
Definition: PluginMenus.cpp:66
BaseItemSharedPtr ExtraScriptablesIIMenu()
BaseItemSharedPtr ExtraScriptablesIMenu()
void AddEffectMenuItemGroup(MenuTable::BaseItemPtrs &table, const TranslatableStrings &names, const PluginIDs &plugs, const std::vector< CommandFlag > &flags, bool isDefault)
const ReservedCommandFlag & HasLastGeneratorFlag()
MenuTable::BaseItemPtrs PopulateMacrosMenu(CommandFlag flags)
Options && IsEffect(bool value=true) &&
Options && AllowInMacros(int value=1) &&
void OnManageAnalyzers(const CommandContext &context)
void OnRepeatLastTool(const CommandContext &context)
void OnApplyMacroDirectlyByName(const CommandContext &context, const MacroID &Name)
void OnRepeatLastGenerator(const CommandContext &context)
void OnScreenshot(const CommandContext &context)
void OnAudacityCommand(const CommandContext &ctx)
void OnResetConfig(const CommandContext &context)
void OnManageMacros(const CommandContext &context)
void OnManageTools(const CommandContext &context)
void OnApplyMacrosPalette(const CommandContext &context)
void OnAnalyzer2(wxCommandEvent &evt)
void OnDetectUpstreamDropouts(const CommandContext &context)
void OnSimulateRecordingErrors(const CommandContext &context)
void OnApplyMacroDirectly(const CommandContext &context)
void OnRepeatLastAnalyzer(const CommandContext &context)
void OnManageEffects(const CommandContext &context)
void OnBenchmark(const CommandContext &context)
void OnManageGenerators(const CommandContext &context)
void OnRepeatLastEffect(const CommandContext &context)
void OnEffect(const CommandContext &context)
void OnWriteJournal(const CommandContext &)