From 9759c6bd4fa0c53585aae36c58af7fa6852fc1b6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 23 Oct 2018 10:50:28 -0400 Subject: [PATCH] Plugin Menus --- lib-src/mod-nyq-bench/NyqBench.cpp | 2 +- src/BatchCommands.cpp | 4 +- src/Menus.cpp | 1052 +-------------------------- src/Menus.h | 27 +- src/Project.cpp | 4 +- src/commands/CommandManager.cpp | 4 +- src/effects/Effect.cpp | 2 +- src/effects/EffectRack.cpp | 2 +- src/menus/PluginMenus.cpp | 1089 ++++++++++++++++++++++++++++ src/menus/TrackMenus.cpp | 4 +- 10 files changed, 1112 insertions(+), 1078 deletions(-) diff --git a/lib-src/mod-nyq-bench/NyqBench.cpp b/lib-src/mod-nyq-bench/NyqBench.cpp index 33eea9095..3ea86f6d9 100755 --- a/lib-src/mod-nyq-bench/NyqBench.cpp +++ b/lib-src/mod-nyq-bench/NyqBench.cpp @@ -1403,7 +1403,7 @@ void NyqBench::OnGo(wxCommandEvent & e) mRunning = true; UpdateWindowUI(); - GetMenuCommandHandler(*p).DoEffect(ID, CommandContext(*p), 0); + PluginActions::DoEffect(ID, CommandContext(*p), 0); mRunning = false; UpdateWindowUI(); diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index c5b3ffa79..d470f40d1 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -720,14 +720,14 @@ bool MacroCommands::ApplyEffectCommand( { if( plug->GetPluginType() == PluginTypeAudacityCommand ) // and apply the effect... - res = GetMenuCommandHandler(*project).DoAudacityCommand(ID, + res = PluginActions::DoAudacityCommand(ID, Context, MenuCommandHandler::OnEffectFlags::kConfigured | MenuCommandHandler::OnEffectFlags::kSkipState | MenuCommandHandler::OnEffectFlags::kDontRepeatLast); else // and apply the effect... - res = GetMenuCommandHandler(*project).DoEffect(ID, + res = PluginActions::DoEffect(ID, Context, MenuCommandHandler::OnEffectFlags::kConfigured | MenuCommandHandler::OnEffectFlags::kSkipState | diff --git a/src/Menus.cpp b/src/Menus.cpp index 07ebb6a21..207f25df6 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -58,8 +58,6 @@ menu items. #include #include -#include "FreqWindow.h" -#include "effects/Contrast.h" #include "TrackPanel.h" #include "effects/EffectManager.h" @@ -80,17 +78,13 @@ menu items. #include "Internat.h" #include "FileFormats.h" #include "ModuleManager.h" -#include "PluginManager.h" #include "Prefs.h" #ifdef USE_MIDI #include "NoteTrack.h" #endif // USE_MIDI #include "AboutDialog.h" -#include "Benchmark.h" -#include "Screenshot.h" #include "ondemand/ODManager.h" -#include "BatchProcessDialog.h" #include "prefs/BatchPrefs.h" #include "toolbars/ToolManager.h" @@ -123,26 +117,6 @@ menu items. #include "widgets/ErrorDialog.h" #include "./commands/AudacityCommand.h" -static MenuTable::BaseItemPtrs PopulateMacrosMenu( - CommandFlag flags ); -static MenuTable::BaseItemPtrs PopulateEffectsMenu( - EffectType type, - CommandFlag batchflags, - CommandFlag realflags); -static void AddEffectMenuItems( - MenuTable::BaseItemPtrs &table, - std::vector & plugs, - CommandFlag batchflags, - CommandFlag realflags, - bool isDefault); -static void AddEffectMenuItemGroup( - MenuTable::BaseItemPtrs &table, - const wxArrayString & names, - const std::vector &vHasDialog, - const PluginIDList & plugs, - const std::vector & flags, - bool isDefault); - static const AudacityProject::RegisteredAttachedObjectFactory factory{ []{ return std::make_unique< MenuCommandHandler >(); } }; @@ -179,128 +153,6 @@ MenuCreator::~MenuCreator() { } -#include "commands/ScreenshotCommand.h" - - -// -// Effects menu arrays -// -static bool SortEffectsByName(const PluginDescriptor *a, const PluginDescriptor *b) -{ - auto akey = a->GetSymbol().Translation(); - auto bkey = b->GetSymbol().Translation(); - - akey += a->GetPath(); - bkey += b->GetPath(); - - return akey.CmpNoCase(bkey) < 0; -} - -static bool SortEffectsByPublisher(const PluginDescriptor *a, const PluginDescriptor *b) -{ - auto &em = EffectManager::Get(); - auto akey = em.GetVendorName(a->GetID()); - auto bkey = em.GetVendorName(b->GetID()); - - if (akey.IsEmpty()) - { - akey = _("Uncategorized"); - } - if (bkey.IsEmpty()) - { - bkey = _("Uncategorized"); - } - - akey += a->GetSymbol().Translation(); - bkey += b->GetSymbol().Translation(); - - akey += a->GetPath(); - bkey += b->GetPath(); - - return akey.CmpNoCase(bkey) < 0; -} - -static bool SortEffectsByPublisherAndName(const PluginDescriptor *a, const PluginDescriptor *b) -{ - auto &em = EffectManager::Get(); - auto akey = em.GetVendorName(a->GetID()); - auto bkey = em.GetVendorName(b->GetID()); - - if (a->IsEffectDefault()) - { - akey = wxEmptyString; - } - if (b->IsEffectDefault()) - { - bkey = wxEmptyString; - } - - akey += a->GetSymbol().Translation(); - bkey += b->GetSymbol().Translation(); - - akey += a->GetPath(); - bkey += b->GetPath(); - - return akey.CmpNoCase(bkey) < 0; -} - -static bool SortEffectsByTypeAndName(const PluginDescriptor *a, const PluginDescriptor *b) -{ - auto &em = EffectManager::Get(); - auto akey = em.GetEffectFamilyName(a->GetID()); - auto bkey = em.GetEffectFamilyName(b->GetID()); - - if (akey.IsEmpty()) - { - akey = _("Uncategorized"); - } - if (bkey.IsEmpty()) - { - bkey = _("Uncategorized"); - } - - if (a->IsEffectDefault()) - { - akey = wxEmptyString; - } - if (b->IsEffectDefault()) - { - bkey = wxEmptyString; - } - - akey += a->GetSymbol().Translation(); - bkey += b->GetSymbol().Translation(); - - akey += a->GetPath(); - bkey += b->GetPath(); - - return akey.CmpNoCase(bkey) < 0; -} - -static bool SortEffectsByType(const PluginDescriptor *a, const PluginDescriptor *b) -{ - auto &em = EffectManager::Get(); - auto akey = em.GetEffectFamilyName(a->GetID()); - auto bkey = em.GetEffectFamilyName(b->GetID()); - - if (akey.IsEmpty()) - { - akey = _("Uncategorized"); - } - if (bkey.IsEmpty()) - { - bkey = _("Uncategorized"); - } - - akey += a->GetSymbol().Translation(); - bkey += b->GetSymbol().Translation(); - - akey += a->GetPath(); - bkey += b->GetPath(); - - return akey.CmpNoCase(bkey) < 0; -} - void MenuCommandHandler::UpdatePrefs() { gPrefs->Read(wxT("/GUI/CircularTrackNavigation"), &mCircularTrackNavigation, @@ -504,11 +356,14 @@ MenuTable::BaseItemPtr ExtraPlayAtSpeedMenu( AudacityProject & ); MenuTable::BaseItemPtr TracksMenu( AudacityProject& ); MenuTable::BaseItemPtr ExtraTrackMenu( AudacityProject & ); -namespace { MenuTable::BaseItemPtr GenerateMenu( AudacityProject& ); MenuTable::BaseItemPtr EffectMenu( AudacityProject& ); MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject& ); MenuTable::BaseItemPtr ToolsMenu( AudacityProject& ); +MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & ); +MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & ); + +namespace { MenuTable::BaseItemPtr WindowMenu( AudacityProject& ); MenuTable::BaseItemPtr ExtraMenu( AudacityProject& ); @@ -516,8 +371,6 @@ MenuTable::BaseItemPtr ExtraMixerMenu( AudacityProject & ); MenuTable::BaseItemPtr ExtraDeviceMenu( AudacityProject & ); MenuTable::BaseItemPtr ExtraGlobalCommands( AudacityProject & ); MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & ); -MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & ); -MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & ); MenuTable::BaseItemPtr ExtraMiscItems( AudacityProject & ); MenuTable::BaseItemPtr HelpMenu( AudacityProject& ); @@ -564,158 +417,6 @@ static const auto menuTree = MenuTable::Items( namespace { -MenuTable::BaseItemPtr GenerateMenu( AudacityProject & ) -{ - using namespace MenuTable; - // All of this is a bit hacky until we can get more things connected into - // the plugin manager...sorry! :-( - - return Menu( _("&Generate"), -#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT - Command( wxT("ManageGenerators"), XXO("Add / Remove Plug-ins..."), - FN(OnManageGenerators), AudioIONotBusyFlag ), - - Separator(), - -#endif - - Items( PopulateEffectsMenu( - EffectTypeGenerate, - AudioIONotBusyFlag, - AudioIONotBusyFlag) ) - ); -} - -MenuTable::BaseItemPtr EffectMenu( AudacityProject &project ) -{ - using namespace MenuTable; - // All of this is a bit hacky until we can get more things connected into - // the plugin manager...sorry! :-( - - const auto &lastEffect = GetMenuManager(project).mLastEffect; - wxString buildMenuLabel; - if (!lastEffect.IsEmpty()) { - buildMenuLabel.Printf(_("Repeat %s"), - EffectManager::Get().GetCommandName(lastEffect)); - } - else - buildMenuLabel = _("Repeat Last Effect"); - - return Menu( _("Effe&ct"), -#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT - Command( wxT("ManageEffects"), XXO("Add / Remove Plug-ins..."), - FN(OnManageEffects), AudioIONotBusyFlag ), - - Separator(), - -#endif - Command( wxT("RepeatLastEffect"), buildMenuLabel, false, FN(OnRepeatLastEffect), - AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag | HasLastEffectFlag, wxT("Ctrl+R") ), - - Separator(), - - Items( PopulateEffectsMenu( - EffectTypeProcess, - AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, - IsRealtimeNotActiveFlag ) ) - ); -} - -MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject & ) -{ - using namespace MenuTable; - // All of this is a bit hacky until we can get more things connected into - // the plugin manager...sorry! :-( - - return Menu( _("&Analyze"), -#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT - Command( wxT("ManageAnalyzers"), XXO("Add / Remove Plug-ins..."), - FN(OnManageAnalyzers), AudioIONotBusyFlag ), - - Separator(), - -#endif - - Command( wxT("ContrastAnalyser"), XXO("Contrast..."), FN(OnContrast), - AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag, wxT("Ctrl+Shift+T") ), - Command( wxT("PlotSpectrum"), XXO("Plot Spectrum..."), FN(OnPlotSpectrum), - AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag ), - - Items( PopulateEffectsMenu( - EffectTypeAnalyze, - AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, - IsRealtimeNotActiveFlag ) ) - ); -} - -MenuTable::BaseItemPtr ToolsMenu( AudacityProject & ) -{ - using namespace MenuTable; - using Options = CommandManager::Options; - - return Menu( _("T&ools"), - -#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT - Command( wxT("ManageTools"), XXO("Add / Remove Plug-ins..."), - FN(OnManageTools), AudioIONotBusyFlag ), - - //Separator(), - -#endif - - Command( wxT("ManageMacros"), XXO("&Macros..."), - FN(OnManageMacros), AudioIONotBusyFlag ), - - Menu( _("&Apply Macro"), - // Palette has no access key to ensure first letter navigation of sub menu - Command( wxT("ApplyMacrosPalette"), XXO("Palette..."), - FN(OnApplyMacrosPalette), AudioIONotBusyFlag ), - - Separator(), - - Items( PopulateMacrosMenu( AudioIONotBusyFlag ) ) - ), - - Separator(), - - Command( wxT("FancyScreenshot"), XXO("&Screenshot..."), - FN(OnScreenshot), AudioIONotBusyFlag ), - -// PRL: team consensus for 2.2.0 was, we let end users have this diagnostic, -// as they used to in 1.3.x -//#ifdef IS_ALPHA - // TODO: What should we do here? Make benchmark a plug-in? - // Easy enough to do. We'd call it mod-self-test. - Command( wxT("Benchmark"), XXO("&Run Benchmark..."), - FN(OnBenchmark), AudioIONotBusyFlag ), -//#endif - - Separator(), - - Items( PopulateEffectsMenu( - EffectTypeTool, - AudioIONotBusyFlag, - AudioIONotBusyFlag ) ) - -#ifdef IS_ALPHA - , - - Separator(), - - Command( wxT("SimulateRecordingErrors"), - XXO("Simulate Recording Errors"), - FN(OnSimulateRecordingErrors), - AudioIONotBusyFlag, - Options{}.CheckState( gAudioIO->mSimulateRecordingErrors ) ), - Command( wxT("DetectUpstreamDropouts"), - XXO("Detect Upstream Dropouts"), - FN(OnDetectUpstreamDropouts), - AudioIONotBusyFlag, - Options{}.CheckState( gAudioIO->mDetectUpstreamDropouts ) ) -#endif - ); -} - MenuTable::BaseItemPtr WindowMenu( AudacityProject & ) { #ifdef __WXMAC__ @@ -838,90 +539,6 @@ MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & ) ); } -MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & ) -{ - using namespace MenuTable; - - // These are the more useful to VI user Scriptables. - // i18n-hint: Scriptables are commands normally used from Python, Perl etc. - return Menu( _("Script&ables I"), - // Note that the PLUGIN_SYMBOL must have a space between words, - // whereas the short-form used here must not. - // (So if you did write "CompareAudio" for the PLUGIN_SYMBOL name, then - // you would have to use "Compareaudio" here.) - Command( wxT("SelectTime"), XXO("Select Time..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SelectFrequencies"), XXO("Select Frequencies..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SelectTracks"), XXO("Select Tracks..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetTrackStatus"), XXO("Set Track Status..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetTrackAudio"), XXO("Set Track Audio..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetTrackVisuals"), XXO("Set Track Visuals..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("GetPreference"), XXO("Get Preference..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetPreference"), XXO("Set Preference..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetClip"), XXO("Set Clip..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetEnvelope"), XXO("Set Envelope..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetLabel"), XXO("Set Label..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetProject"), XXO("Set Project..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ) - ); -} - -MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & ) -{ - using namespace MenuTable; - - // Less useful to VI users. - return Menu( _("Scripta&bles II"), - Command( wxT("Select"), XXO("Select..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SetTrack"), XXO("Set Track..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("GetInfo"), XXO("Get Info..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("Message"), XXO("Message..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("Help"), XXO("Help..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("Import2"), XXO("Import..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("Export2"), XXO("Export..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("OpenProject2"), XXO("Open Project..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("SaveProject2"), XXO("Save Project..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("Drag"), XXO("Move Mouse..."), FN(OnAudacityCommand), - AudioIONotBusyFlag ), - Command( wxT("CompareAudio"), XXO("Compare Audio..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ), - // i18n-hint: Screenshot in the help menu has a much bigger dialog. - Command( wxT("Screenshot"), XXO("Screenshot (short format)..."), - FN(OnAudacityCommand), - AudioIONotBusyFlag ) - ); -} - MenuTable::BaseItemPtr ExtraWindowItems( AudacityProject & ) { #ifdef __WXMAC__ @@ -1052,353 +669,6 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project) } #undef XXO - - - -MenuTable::BaseItemPtrs PopulateMacrosMenu( CommandFlag flags ) -{ - MenuTable::BaseItemPtrs result; - wxArrayString names = MacroCommands::GetNames(); - int i; - - for (i = 0; i < (int)names.GetCount(); i++) { - wxString MacroID = ApplyMacroDialog::MacroIdOfName( names[i] ); - result.push_back( MenuTable::Command( MacroID, - names[i], false, FN(OnApplyMacroDirectly), - flags ) ); - } - - return result; -} - - -/// The effects come from a plug in list -/// This code iterates through the list, adding effects into -/// the menu. -MenuTable::BaseItemPtrs PopulateEffectsMenu( - EffectType type, - CommandFlag batchflags, - CommandFlag realflags) -{ - MenuTable::BaseItemPtrs result; - PluginManager & pm = PluginManager::Get(); - - std::vector defplugs; - std::vector optplugs; - - const PluginDescriptor *plug = pm.GetFirstPluginForEffectType(type); - while (plug) - { - if ( !plug->IsEnabled() ){ - ;// don't add to menus! - } - else if (plug->IsEffectDefault() -#ifdef EXPERIMENTAL_DA - // Move Nyquist prompt into nyquist group. - && (plug->GetSymbol() != IdentInterfaceSymbol("Nyquist Effects Prompt")) - && (plug->GetSymbol() != IdentInterfaceSymbol("Nyquist Tools Prompt")) - && (plug->GetSymbol() != IdentInterfaceSymbol("Nyquist Prompt")) -#endif - ) - defplugs.push_back(plug); - else - optplugs.push_back(plug); - plug = pm.GetNextPluginForEffectType(type); - } - - wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name")); - - using Comparator = bool(*)(const PluginDescriptor*, const PluginDescriptor*); - Comparator comp1, comp2; - if (groupby == wxT("sortby:name")) - comp1 = comp2 = SortEffectsByName; - else if (groupby == wxT("sortby:publisher:name")) - comp1 = SortEffectsByName, comp2 = SortEffectsByPublisherAndName; - else if (groupby == wxT("sortby:type:name")) - comp1 = SortEffectsByName, comp2 = SortEffectsByTypeAndName; - else if (groupby == wxT("groupby:publisher")) - comp1 = comp2 = SortEffectsByPublisher; - else if (groupby == wxT("groupby:type")) - comp1 = comp2 = SortEffectsByType; - else // name - comp1 = comp2 = SortEffectsByName; - - std::sort( defplugs.begin(), defplugs.end(), comp1 ); - if ( comp1 != comp2 ) - std::stable_sort( optplugs.begin(), optplugs.end(), comp2 ); - - AddEffectMenuItems( result, defplugs, batchflags, realflags, true ); - - if (defplugs.size() && optplugs.size()) - result.push_back( MenuTable::Separator() ); - - AddEffectMenuItems( result, optplugs, batchflags, realflags, false ); - - return result; -} - -void AddEffectMenuItems( - MenuTable::BaseItemPtrs &table, - std::vector & plugs, - CommandFlag batchflags, - CommandFlag realflags, - bool isDefault) -{ - size_t pluginCnt = plugs.size(); - - wxString groupBy = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name")); - - bool grouped = false; - if (groupBy.StartsWith(wxT("groupby"))) - { - grouped = true; - } - - std::vector vHasDialog; - wxArrayString groupNames; - PluginIDList groupPlugs; - std::vector groupFlags; - if (grouped) - { - wxString last; - wxString current; - - for (size_t i = 0; i < pluginCnt; i++) - { - const PluginDescriptor *plug = plugs[i]; - - bool hasDialog = plug->GetSymbol().Msgid().Contains("..."); - auto name = plug->GetSymbol().Translation(); - - if (plug->IsEffectInteractive()) - { - name += wxT("..."); - } - - if (groupBy == wxT("groupby:publisher")) - { - current = EffectManager::Get().GetVendorName(plug->GetID()); - if (current.IsEmpty()) - { - current = _("Unknown"); - } - } - else if (groupBy == wxT("groupby:type")) - { - current = EffectManager::Get().GetEffectFamilyName(plug->GetID()); - if (current.IsEmpty()) - { - current = _("Unknown"); - } - } - - if (current != last) - { - using namespace MenuTable; - BaseItemPtrs temp; - bool bInSubmenu = !last.IsEmpty() && (groupNames.Count() > 1); - - AddEffectMenuItemGroup(temp, - groupNames, vHasDialog, - groupPlugs, groupFlags, isDefault); - - table.push_back( MenuOrItems( - ( bInSubmenu ? last : wxString{} ), std::move( temp ) - ) ); - - groupNames.Clear(); - vHasDialog.clear(); - groupPlugs.Clear(); - groupFlags.clear(); - last = current; - } - - groupNames.Add(name); - vHasDialog.push_back(hasDialog); - groupPlugs.Add(plug->GetID()); - groupFlags.push_back(plug->IsEffectRealtime() ? realflags : batchflags); - } - - if (groupNames.GetCount() > 0) - { - using namespace MenuTable; - BaseItemPtrs temp; - bool bInSubmenu = groupNames.Count() > 1; - - AddEffectMenuItemGroup(temp, - groupNames, vHasDialog, groupPlugs, groupFlags, isDefault); - - table.push_back( MenuOrItems( - ( bInSubmenu ? current : wxString{} ), std::move( temp ) - ) ); - } - } - else - { - for (size_t i = 0; i < pluginCnt; i++) - { - const PluginDescriptor *plug = plugs[i]; - - bool hasDialog = plug->GetSymbol().Msgid().Contains("..."); - auto name = plug->GetSymbol().Translation(); - - if (plug->IsEffectInteractive()) - { - name += wxT("..."); - } - - wxString group = wxEmptyString; - if (groupBy == wxT("sortby:publisher:name")) - { - group = EffectManager::Get().GetVendorName(plug->GetID()); - } - else if (groupBy == wxT("sortby:type:name")) - { - group = EffectManager::Get().GetEffectFamilyName(plug->GetID()); - } - - if (plug->IsEffectDefault()) - { - group = wxEmptyString; - } - - if (!group.IsEmpty()) - { - group += wxT(": "); - } - - groupNames.Add(group + name); - vHasDialog.push_back(hasDialog); - groupPlugs.Add(plug->GetID()); - groupFlags.push_back(plug->IsEffectRealtime() ? realflags : batchflags); - } - - if (groupNames.GetCount() > 0) - { - AddEffectMenuItemGroup(table, groupNames, vHasDialog, groupPlugs, groupFlags, isDefault); - } - - } - - return; -} - -void AddEffectMenuItemGroup( - MenuTable::BaseItemPtrs &table, - const wxArrayString & names, - const std::vector &vHasDialog, - const PluginIDList & plugs, - const std::vector & flags, - bool isDefault) -{ - const int namesCnt = (int) names.GetCount(); - int perGroup; - -#if defined(__WXGTK__) - gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 15); -#else - gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 0); -#endif - - int groupCnt = namesCnt; - for (int i = 0; i < namesCnt; i++) - { - while (i + 1 < namesCnt && names[i].IsSameAs(names[i + 1])) - { - i++; - groupCnt--; - } - } - - // The "default" effects shouldn't be broken into subgroups - if (namesCnt > 0 && isDefault) - { - perGroup = 0; - } - - int max = perGroup; - int items = perGroup; - - if (max > groupCnt) - { - max = 0; - } - - using namespace MenuTable; - auto pTable = &table; - BaseItemPtrs temp1; - - int groupNdx = 0; - for (int i = 0; i < namesCnt; i++) - { - if (max > 0 && items == max) - { - // start collecting items for the next submenu - pTable = &temp1; - } - - if (i + 1 < namesCnt && names[i].IsSameAs(names[i + 1])) - { - // collect a sub-menu for like-named items - const wxString name = names[i]; - BaseItemPtrs temp2; - while (i < namesCnt && names[i].IsSameAs(name)) - { - const PluginDescriptor *plug = PluginManager::Get().GetPlugin(plugs[i]); - wxString item = plug->GetPath(); - if( plug->GetPluginType() == PluginTypeEffect ) - temp2.push_back( Command( item, - item, - item.Contains("..."), - FN(OnEffect), - flags[i], - CommandManager::Options{} - .IsEffect().Parameter( plugs[i] ) ) ); - - i++; - } - pTable->push_back( Menu( name, std::move( temp2 ) ) ); - i--; - } - else - { - // collect one item - const PluginDescriptor *plug = PluginManager::Get().GetPlugin(plugs[i]); - if( plug->GetPluginType() == PluginTypeEffect ) - pTable->push_back( Command( names[i], - names[i], - vHasDialog[i], - FN(OnEffect), - flags[i], - CommandManager::Options{} - .IsEffect().Parameter( plugs[i] ) ) ); - } - - if (max > 0) - { - items--; - if (items == 0 || i + 1 == namesCnt) - { - int end = groupNdx + max; - if (end + 1 > groupCnt) - { - end = groupCnt; - } - // Done collecting - table.push_back( Menu( - wxString::Format(_("Plug-in %d to %d"), groupNdx + 1, end), - std::move( temp1 ) - ) ); - items = max; - pTable = &table; - } - groupNdx++; - } - } - - return; -} - #undef FN // TODO: This surely belongs in CommandManager? @@ -2510,191 +1780,6 @@ void MenuCommandHandler::OnInputGainDec(const CommandContext &context) } } -/// DoAudacityCommand() takes a PluginID and executes the assocated effect. -/// -/// At the moment flags are used only to indicate whether to prompt for parameters, -bool MenuCommandHandler::DoAudacityCommand(const PluginID & ID, const CommandContext & context, int flags) -{ - auto &project = context.project; - const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID); - if (!plug) - return false; - - if (flags & OnEffectFlags::kConfigured) - { - TransportActions::DoStop(project); -// SelectAllIfNone(); - } - - EffectManager & em = EffectManager::Get(); - bool success = em.DoAudacityCommand(ID, - context, - &project, - (flags & OnEffectFlags::kConfigured) == 0); - - if (!success) - return false; - -/* - if (em.GetSkipStateFlag()) - flags = flags | OnEffectFlags::kSkipState; - - if (!(flags & OnEffectFlags::kSkipState)) - { - wxString shortDesc = em.GetCommandName(ID); - wxString longDesc = em.GetCommandDescription(ID); - PushState(longDesc, shortDesc); - } -*/ - project.RedrawProject(); - return true; -} - - - -// -// Effect Menus -// - -/// DoEffect() takes a PluginID and has the EffectManager execute the assocated effect. -/// -/// At the moment flags are used only to indicate whether to prompt for parameters, -/// whether to save the state to history and whether to allow 'Repeat Last Effect'. -bool MenuCommandHandler::DoEffect( - const PluginID & ID, const CommandContext &context, int flags) -{ - AudacityProject &project = context.project; - auto tracks = project.GetTracks(); - auto trackPanel = project.GetTrackPanel(); - auto trackFactory = project.GetTrackFactory(); - auto rate = project.GetRate(); - auto &selectedRegion = project.GetSelection(); - auto commandManager = project.GetCommandManager(); - - const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID); - if (!plug) - return false; - - EffectType type = plug->GetEffectType(); - - // Make sure there's no activity since the effect is about to be applied - // to the project's tracks. Mainly for Apply during RTP, but also used - // for batch commands - if (flags & MenuCommandHandler::OnEffectFlags::kConfigured) - { - TransportActions::DoStop(project); - project.SelectAllIfNone(); - } - - wxGetApp().SetMissingAliasedFileWarningShouldShow(true); - - auto nTracksOriginally = project.GetTrackCount(); - wxWindow *focus = wxWindow::FindFocus(); - wxWindow *parent = nullptr; - if (focus != nullptr) { - parent = focus->GetParent(); - } - - bool success = false; - auto cleanup = finally( [&] { - - if (!success) { - // For now, we're limiting realtime preview to a single effect, so - // make sure the menus reflect that fact that one may have just been - // opened. - GetMenuManager(project).UpdateMenus(project, false); - } - - } ); - - int count = 0; - bool clean = true; - for (auto t : tracks->Selected< const WaveTrack >()) { - if (t->GetEndTime() != 0.0) - clean = false; - count++; - } - - EffectManager & em = EffectManager::Get(); - - success = em.DoEffect(ID, &project, rate, - tracks, trackFactory, &selectedRegion, - (flags & MenuCommandHandler::OnEffectFlags::kConfigured) == 0); - - if (!success) - return false; - - if (em.GetSkipStateFlag()) - flags = flags | MenuCommandHandler::OnEffectFlags::kSkipState; - - if (!(flags & MenuCommandHandler::OnEffectFlags::kSkipState)) - { - wxString shortDesc = em.GetCommandName(ID); - wxString longDesc = em.GetCommandDescription(ID); - project.PushState(longDesc, shortDesc); - } - - if (!(flags & MenuCommandHandler::OnEffectFlags::kDontRepeatLast)) - { - // Only remember a successful effect, don't remember insert, - // or analyze effects. - if (type == EffectTypeProcess) { - wxString shortDesc = em.GetCommandName(ID); - GetMenuManager(project).mLastEffect = ID; - wxString lastEffectDesc; - /* i18n-hint: %s will be the name of the effect which will be - * repeated if this menu item is chosen */ - lastEffectDesc.Printf(_("Repeat %s"), shortDesc); - commandManager->Modify(wxT("RepeatLastEffect"), lastEffectDesc); - } - } - - //STM: - //The following automatically re-zooms after sound was generated. - // IMO, it was disorienting, removing to try out without re-fitting - //mchinen:12/14/08 reapplying for generate effects - if (type == EffectTypeGenerate) - { - if (count == 0 || (clean && selectedRegion.t0() == 0.0)) - ViewActions::DoZoomFit(project); - // trackPanel->Refresh(false); - } - project.RedrawProject(); - if (focus != nullptr && focus->GetParent()==parent) { - focus->SetFocus(); - } - - // A fix for Bug 63 - // New tracks added? Scroll them into view so that user sees them. - // Don't care what track type. An analyser might just have added a - // Label track and we want to see it. - if( project.GetTrackCount() > nTracksOriginally ){ - // 0.0 is min scroll position, 1.0 is max scroll position. - trackPanel->VerticalScroll( 1.0 ); - } else { - trackPanel->EnsureVisible(trackPanel->GetFirstSelectedTrack()); - trackPanel->Refresh(false); - } - - return true; -} - -void MenuCommandHandler::OnEffect(const CommandContext &context) -{ - DoEffect(context.parameter, context, 0); -} - -void MenuCommandHandler::OnRepeatLastEffect(const CommandContext &context) -{ - auto lastEffect = GetMenuManager(context.project).mLastEffect; - if (!lastEffect.IsEmpty()) - { - DoEffect(lastEffect, - context, OnEffectFlags::kConfigured); - } -} - - void MenuCommandHandler::RebuildAllMenuBars() { for( size_t i = 0; i < gAudacityProjects.size(); i++ ) { @@ -2714,46 +1799,6 @@ void MenuCommandHandler::RebuildAllMenuBars() } } -void MenuCommandHandler::DoManagePluginsMenu -(AudacityProject &project, EffectType type) -{ - if (PluginManager::Get().ShowManager(&project, type)) - RebuildAllMenuBars(); -} - -void MenuCommandHandler::OnManageGenerators(const CommandContext &context) -{ - auto &project = context.project; - DoManagePluginsMenu(project, EffectTypeGenerate); -} - -void MenuCommandHandler::OnManageEffects(const CommandContext &context) -{ - auto &project = context.project; - DoManagePluginsMenu(project, EffectTypeProcess); -} - -void MenuCommandHandler::OnManageAnalyzers(const CommandContext &context) -{ - auto &project = context.project; - DoManagePluginsMenu(project, EffectTypeAnalyze); -} - -void MenuCommandHandler::OnManageTools(const CommandContext &context ) -{ - auto &project = context.project; - DoManagePluginsMenu(project, EffectTypeTool); -} - - -void MenuCommandHandler::OnAudacityCommand(const CommandContext & ctx) -{ - wxLogDebug( "Command was: %s", ctx.parameter); - DoAudacityCommand(EffectManager::Get().GetEffectByIdentifier(ctx.parameter), - ctx, - OnEffectFlags::kNone); // Not configured, so prompt user. -} - // // File Menu // @@ -2876,64 +1921,6 @@ void AudacityProject::ZoomOutByFactor( double ZoomFactor ) TP_ScrollWindow(newh); } -void MenuCommandHandler::OnApplyMacroDirectly(const CommandContext &context ) -{ - auto &project = context.project; - - //wxLogDebug( "Macro was: %s", context.parameter); - ApplyMacroDialog dlg( &project ); - wxString Name = context.parameter; - -// We used numbers previously, but macros could get renumbered, making -// macros containing macros unpredictable. -#ifdef MACROS_BY_NUMBERS - long item=0; - // Take last three letters (of e.g. Macro007) and convert to a number. - Name.Mid( Name.Length() - 3 ).ToLong( &item, 10 ); - dlg.ApplyMacroToProject( item, false ); -#else - dlg.ApplyMacroToProject( Name, false ); -#endif - MenuManager::ModifyUndoMenuItems( project ); -} - -void MenuCommandHandler::OnApplyMacrosPalette(const CommandContext &context ) -{ - auto &project = context.project; - project.GetMacrosWindow( false, true ); -} - -void MenuCommandHandler::OnManageMacros(const CommandContext &context ) -{ - auto &project = context.project; - project.GetMacrosWindow( true, true ); -} - -void MenuCommandHandler::OnPlotSpectrum(const CommandContext &context) -{ - auto &project = context.project; - auto freqWindow = project.GetFreqWindow(true); - - - if( ScreenshotCommand::MayCapture( freqWindow ) ) - return; - freqWindow->Show(true); - freqWindow->Raise(); - freqWindow->SetFocus(); -} - -void MenuCommandHandler::OnContrast(const CommandContext &context) -{ - auto &project = context.project; - auto contrastDialog = project.GetContrastDialog(true); - - - contrastDialog->CentreOnParent(); - if( ScreenshotCommand::MayCapture( contrastDialog ) ) - return; - contrastDialog->Show(); -} - // // Help Menu // @@ -3004,12 +1991,6 @@ void MenuCommandHandler::OnShowLog(const CommandContext &WXUNUSED(context) ) } } -void MenuCommandHandler::OnBenchmark(const CommandContext &context) -{ - auto &project = context.project; - ::RunBenchmark(&project); -} - #if defined(EXPERIMENTAL_CRASH_REPORT) void MenuCommandHandler::OnCrashReport(const CommandContext &WXUNUSED(context) ) { @@ -3022,31 +2003,6 @@ void MenuCommandHandler::OnCrashReport(const CommandContext &WXUNUSED(context) ) } #endif -void MenuCommandHandler::OnSimulateRecordingErrors(const CommandContext &context) -{ - auto &project = context.project; - auto commandManager = project.GetCommandManager(); - - bool &setting = gAudioIO->mSimulateRecordingErrors; - commandManager->Check(wxT("SimulateRecordingErrors"), !setting); - setting = !setting; -} - -void MenuCommandHandler::OnDetectUpstreamDropouts(const CommandContext &context) -{ - auto &project = context.project; - auto commandManager = project.GetCommandManager(); - - bool &setting = gAudioIO->mDetectUpstreamDropouts; - commandManager->Check(wxT("DetectUpstreamDropouts"), !setting); - setting = !setting; -} - -void MenuCommandHandler::OnScreenshot(const CommandContext &WXUNUSED(context) ) -{ - ::OpenScreenshotTools(); -} - void MenuCommandHandler::OnAudioDeviceInfo(const CommandContext &context) { auto &project = context.project; diff --git a/src/Menus.h b/src/Menus.h index 9f292514a..32f145488 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -97,9 +97,6 @@ void OnCheckDependencies(const CommandContext &context ); public: -void OnPlotSpectrum(const CommandContext &context ); -void OnContrast(const CommandContext &context ); - // Effect Menu struct OnEffectFlags @@ -115,20 +112,7 @@ struct OnEffectFlags static const int kDontRepeatLast = 0x04; }; -bool DoEffect(const PluginID & ID, const CommandContext & context, int flags); -void OnEffect(const CommandContext &context ); -void OnRepeatLastEffect(const CommandContext &context ); -bool DoAudacityCommand(const PluginID & ID, const CommandContext &, int flags); -void OnApplyMacroDirectly(const CommandContext &context ); -void OnApplyMacrosPalette(const CommandContext &context ); -void OnManageMacros(const CommandContext &context ); -void OnAudacityCommand(const CommandContext &context ); -void DoManagePluginsMenu(AudacityProject &project, EffectType Type); static void RebuildAllMenuBars(); -void OnManageGenerators(const CommandContext &context ); -void OnManageEffects(const CommandContext &context ); -void OnManageAnalyzers(const CommandContext &context ); -void OnManageTools(const CommandContext &context ); // Help Menu @@ -140,13 +124,9 @@ void OnCheckForUpdates(const CommandContext &context ); void MayCheckForUpdates(AudacityProject &project); void OnShowLog(const CommandContext &context ); void OnHelpWelcome(const CommandContext &context ); -void OnBenchmark(const CommandContext &context ); #if defined(EXPERIMENTAL_CRASH_REPORT) void OnCrashReport(const CommandContext &context ); #endif -void OnSimulateRecordingErrors(const CommandContext &context ); -void OnDetectUpstreamDropouts(const CommandContext &context ); -void OnScreenshot(const CommandContext &context ); void OnAudioDeviceInfo(const CommandContext &context ); #ifdef EXPERIMENTAL_MIDI_OUT void OnMidiDeviceInfo(const CommandContext &context ); @@ -267,6 +247,13 @@ void DoMoveTrack( AudacityProject &project, Track* target, MoveChoice choice ); void DoRemoveTracks( AudacityProject & ); } +namespace PluginActions { +bool DoEffect( + const PluginID & ID, const CommandContext & context, unsigned flags ); +bool DoAudacityCommand( + const PluginID & ID, const CommandContext & context, unsigned flags ); +} + #endif diff --git a/src/Project.cpp b/src/Project.cpp index 3d8a4901b..2679ebf31 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4416,8 +4416,8 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr SelectNone(); SelectAllIfNone(); const CommandContext context( *this); - GetMenuCommandHandler(*this) - .DoEffect(EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")), + PluginActions::DoEffect( + EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")), context, MenuCommandHandler::OnEffectFlags::kConfigured); } diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 0d6800379..748280795 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -1587,7 +1587,9 @@ bool CommandManager::HandleTextualCommand(const wxString & Str, const CommandCon { if (em.GetCommandIdentifier(plug->GetID()).IsSameAs(Str, false)) { - return GetMenuCommandHandler(*proj).DoEffect(plug->GetID(), context, MenuCommandHandler::OnEffectFlags::kConfigured); + return PluginActions::DoEffect( + plug->GetID(), context, + MenuCommandHandler::OnEffectFlags::kConfigured); } plug = pm.GetNextPlugin(PluginTypeEffect); } diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index ecae0d438..22749247d 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -768,7 +768,7 @@ bool Effect::Apply() // This is absolute hackage...but easy and I can't think of another way just now. // // It should callback to the EffectManager to kick off the processing - return GetMenuCommandHandler(project).DoEffect(GetID(), context, + return PluginActions::DoEffect(GetID(), context, MenuCommandHandler::OnEffectFlags::kConfigured); } diff --git a/src/effects/EffectRack.cpp b/src/effects/EffectRack.cpp index 9860593de..b64e86ea9 100644 --- a/src/effects/EffectRack.cpp +++ b/src/effects/EffectRack.cpp @@ -305,7 +305,7 @@ void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt)) { if (mPowerState[i]) { - if (!GetMenuCommandHandler(*project).DoEffect(mEffects[i]->GetID(), + if (!PluginActions::DoEffect(mEffects[i]->GetID(), *project, AudacityProject::OnEffectFlags::kConfigured)) // If any effect fails (or throws), then stop. diff --git a/src/menus/PluginMenus.cpp b/src/menus/PluginMenus.cpp index e69de29bb..25bcdf853 100644 --- a/src/menus/PluginMenus.cpp +++ b/src/menus/PluginMenus.cpp @@ -0,0 +1,1089 @@ +#include "../AudacityApp.h" +#include "../AudioIO.h" +#include "../BatchProcessDialog.h" +#include "../Benchmark.h" +#include "../Experimental.h" +#include "../FreqWindow.h" +#include "../Menus.h" +#include "../PluginManager.h" +#include "../Prefs.h" +#include "../Project.h" +#include "../Screenshot.h" +#include "../TrackPanel.h" +#include "../WaveTrack.h" +#include "../commands/CommandContext.h" +#include "../commands/CommandManager.h" +#include "../commands/ScreenshotCommand.h" +#include "../effects/Contrast.h" + +// private helper classes and functions +namespace { + +void DoManagePluginsMenu +(AudacityProject &project, EffectType type) +{ + if (PluginManager::Get().ShowManager(&project, type)) + MenuCommandHandler::RebuildAllMenuBars(); +} + +bool CompareEffectsByName(const PluginDescriptor *a, const PluginDescriptor *b) +{ + auto akey = a->GetSymbol().Translation(); + auto bkey = b->GetSymbol().Translation(); + + akey += a->GetPath(); + bkey += b->GetPath(); + + return akey.CmpNoCase(bkey) < 0; +} + +bool CompareEffectsByPublisher( + const PluginDescriptor *a, const PluginDescriptor *b) +{ + auto &em = EffectManager::Get(); + auto akey = em.GetVendorName(a->GetID()); + auto bkey = em.GetVendorName(b->GetID()); + + if (akey.IsEmpty()) + { + akey = _("Uncategorized"); + } + if (bkey.IsEmpty()) + { + bkey = _("Uncategorized"); + } + + akey += a->GetSymbol().Translation(); + bkey += b->GetSymbol().Translation(); + + akey += a->GetPath(); + bkey += b->GetPath(); + + return akey.CmpNoCase(bkey) < 0; +} + +bool CompareEffectsByPublisherAndName( + const PluginDescriptor *a, const PluginDescriptor *b) +{ + auto &em = EffectManager::Get(); + auto akey = em.GetVendorName(a->GetID()); + auto bkey = em.GetVendorName(b->GetID()); + + if (a->IsEffectDefault()) + { + akey = wxEmptyString; + } + if (b->IsEffectDefault()) + { + bkey = wxEmptyString; + } + + akey += a->GetSymbol().Translation(); + bkey += b->GetSymbol().Translation(); + + akey += a->GetPath(); + bkey += b->GetPath(); + + return akey.CmpNoCase(bkey) < 0; +} + +bool CompareEffectsByTypeAndName( + const PluginDescriptor *a, const PluginDescriptor *b) +{ + auto &em = EffectManager::Get(); + auto akey = em.GetEffectFamilyName(a->GetID()); + auto bkey = em.GetEffectFamilyName(b->GetID()); + + if (akey.IsEmpty()) + { + akey = _("Uncategorized"); + } + if (bkey.IsEmpty()) + { + bkey = _("Uncategorized"); + } + + if (a->IsEffectDefault()) + { + akey = wxEmptyString; + } + if (b->IsEffectDefault()) + { + bkey = wxEmptyString; + } + + akey += a->GetSymbol().Translation(); + bkey += b->GetSymbol().Translation(); + + akey += a->GetPath(); + bkey += b->GetPath(); + + return akey.CmpNoCase(bkey) < 0; +} + +bool CompareEffectsByType(const PluginDescriptor *a, const PluginDescriptor *b) +{ + auto &em = EffectManager::Get(); + auto akey = em.GetEffectFamilyName(a->GetID()); + auto bkey = em.GetEffectFamilyName(b->GetID()); + + if (akey.IsEmpty()) + { + akey = _("Uncategorized"); + } + if (bkey.IsEmpty()) + { + bkey = _("Uncategorized"); + } + + akey += a->GetSymbol().Translation(); + bkey += b->GetSymbol().Translation(); + + akey += a->GetPath(); + bkey += b->GetPath(); + + return akey.CmpNoCase(bkey) < 0; +} + +// Forward-declared function has its definition below with OnEffect in view +void AddEffectMenuItemGroup( + MenuTable::BaseItemPtrs &table, + const wxArrayString & names, + const std::vector &vHasDialog, + const PluginIDList & plugs, + const std::vector & flags, + bool isDefault); + +void AddEffectMenuItems( + MenuTable::BaseItemPtrs &table, + std::vector & plugs, + CommandFlag batchflags, + CommandFlag realflags, + bool isDefault) +{ + size_t pluginCnt = plugs.size(); + + wxString groupBy = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name")); + + bool grouped = false; + if (groupBy.StartsWith(wxT("groupby"))) + { + grouped = true; + } + + std::vector vHasDialog; + wxArrayString groupNames; + PluginIDList groupPlugs; + std::vector groupFlags; + if (grouped) + { + wxString last; + wxString current; + + for (size_t i = 0; i < pluginCnt; i++) + { + const PluginDescriptor *plug = plugs[i]; + + bool hasDialog = plug->GetSymbol().Msgid().Contains("..."); + auto name = plug->GetSymbol().Translation(); + + if (plug->IsEffectInteractive()) + { + name += wxT("..."); + } + + if (groupBy == wxT("groupby:publisher")) + { + current = EffectManager::Get().GetVendorName(plug->GetID()); + if (current.IsEmpty()) + { + current = _("Unknown"); + } + } + else if (groupBy == wxT("groupby:type")) + { + current = EffectManager::Get().GetEffectFamilyName(plug->GetID()); + if (current.IsEmpty()) + { + current = _("Unknown"); + } + } + + if (current != last) + { + using namespace MenuTable; + BaseItemPtrs temp; + bool bInSubmenu = !last.IsEmpty() && (groupNames.Count() > 1); + + AddEffectMenuItemGroup(temp, + groupNames, vHasDialog, + groupPlugs, groupFlags, isDefault); + + table.push_back( MenuOrItems( + ( bInSubmenu ? last : wxString{} ), std::move( temp ) + ) ); + + groupNames.Clear(); + vHasDialog.clear(); + groupPlugs.Clear(); + groupFlags.clear(); + last = current; + } + + groupNames.Add(name); + vHasDialog.push_back(hasDialog); + groupPlugs.Add(plug->GetID()); + groupFlags.push_back( + plug->IsEffectRealtime() ? realflags : batchflags); + } + + if (groupNames.GetCount() > 0) + { + using namespace MenuTable; + BaseItemPtrs temp; + bool bInSubmenu = groupNames.Count() > 1; + + AddEffectMenuItemGroup(temp, + groupNames, vHasDialog, groupPlugs, groupFlags, isDefault); + + table.push_back( MenuOrItems( + ( bInSubmenu ? current : wxString{} ), std::move( temp ) + ) ); + } + } + else + { + for (size_t i = 0; i < pluginCnt; i++) + { + const PluginDescriptor *plug = plugs[i]; + + bool hasDialog = plug->GetSymbol().Msgid().Contains("..."); + auto name = plug->GetSymbol().Translation(); + + if (plug->IsEffectInteractive()) + { + name += wxT("..."); + } + + wxString group = wxEmptyString; + if (groupBy == wxT("sortby:publisher:name")) + { + group = EffectManager::Get().GetVendorName(plug->GetID()); + } + else if (groupBy == wxT("sortby:type:name")) + { + group = EffectManager::Get().GetEffectFamilyName(plug->GetID()); + } + + if (plug->IsEffectDefault()) + { + group = wxEmptyString; + } + + if (!group.IsEmpty()) + { + group += wxT(": "); + } + + groupNames.Add(group + name); + vHasDialog.push_back(hasDialog); + groupPlugs.Add(plug->GetID()); + groupFlags.push_back(plug->IsEffectRealtime() ? realflags : batchflags); + } + + if (groupNames.GetCount() > 0) + { + AddEffectMenuItemGroup( + table, groupNames, vHasDialog, groupPlugs, groupFlags, isDefault); + } + + } + + return; +} + +/// The effects come from a plug in list +/// This code iterates through the list, adding effects into +/// the menu. +MenuTable::BaseItemPtrs PopulateEffectsMenu( + EffectType type, + CommandFlag batchflags, + CommandFlag realflags) +{ + MenuTable::BaseItemPtrs result; + PluginManager & pm = PluginManager::Get(); + + std::vector defplugs; + std::vector optplugs; + + const PluginDescriptor *plug = pm.GetFirstPluginForEffectType(type); + while (plug) + { + if ( !plug->IsEnabled() ){ + ;// don't add to menus! + } + else if (plug->IsEffectDefault() +#ifdef EXPERIMENTAL_DA + // Move Nyquist prompt into nyquist group. + && (plug->GetSymbol() != + IdentInterfaceSymbol("Nyquist Effects Prompt")) + && (plug->GetSymbol() != IdentInterfaceSymbol("Nyquist Tools Prompt")) + && (plug->GetSymbol() != IdentInterfaceSymbol("Nyquist Prompt")) +#endif + ) + defplugs.push_back(plug); + else + optplugs.push_back(plug); + plug = pm.GetNextPluginForEffectType(type); + } + + wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name")); + + using Comparator = bool(*)(const PluginDescriptor*, const PluginDescriptor*); + Comparator comp1, comp2; + if (groupby == wxT("sortby:name")) + comp1 = comp2 = CompareEffectsByName; + else if (groupby == wxT("sortby:publisher:name")) + comp1 = CompareEffectsByName, comp2 = CompareEffectsByPublisherAndName; + else if (groupby == wxT("sortby:type:name")) + comp1 = CompareEffectsByName, comp2 = CompareEffectsByTypeAndName; + else if (groupby == wxT("groupby:publisher")) + comp1 = comp2 = CompareEffectsByPublisher; + else if (groupby == wxT("groupby:type")) + comp1 = comp2 = CompareEffectsByType; + else // name + comp1 = comp2 = CompareEffectsByName; + + std::sort( defplugs.begin(), defplugs.end(), comp1 ); + if ( comp1 != comp2 ) + std::stable_sort( optplugs.begin(), optplugs.end(), comp2 ); + + AddEffectMenuItems( result, defplugs, batchflags, realflags, true ); + + if (defplugs.size() && optplugs.size()) + result.push_back( MenuTable::Separator() ); + + AddEffectMenuItems( result, optplugs, batchflags, realflags, false ); + + return result; +} + +// Forward-declared function has its definition below with OnApplyMacroDirectly +// in view +MenuTable::BaseItemPtrs PopulateMacrosMenu( CommandFlag flags ); + +} + +namespace PluginActions { + +// exported helper functions + +/// DoEffect() takes a PluginID and has the EffectManager execute the assocated +/// effect. +/// +/// At the moment flags are used only to indicate whether to prompt for +// parameters, whether to save the state to history and whether to allow +/// 'Repeat Last Effect'. +bool DoEffect( + const PluginID & ID, const CommandContext &context, unsigned flags ) +{ + AudacityProject &project = context.project; + auto tracks = project.GetTracks(); + auto trackPanel = project.GetTrackPanel(); + auto trackFactory = project.GetTrackFactory(); + auto rate = project.GetRate(); + auto &selectedRegion = project.GetSelection(); + auto commandManager = project.GetCommandManager(); + + const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID); + if (!plug) + return false; + + EffectType type = plug->GetEffectType(); + + // Make sure there's no activity since the effect is about to be applied + // to the project's tracks. Mainly for Apply during RTP, but also used + // for batch commands + if (flags & MenuCommandHandler::OnEffectFlags::kConfigured) + { + TransportActions::DoStop(project); + project.SelectAllIfNone(); + } + + wxGetApp().SetMissingAliasedFileWarningShouldShow(true); + + auto nTracksOriginally = project.GetTrackCount(); + wxWindow *focus = wxWindow::FindFocus(); + wxWindow *parent = nullptr; + if (focus != nullptr) { + parent = focus->GetParent(); + } + + bool success = false; + auto cleanup = finally( [&] { + + if (!success) { + // For now, we're limiting realtime preview to a single effect, so + // make sure the menus reflect that fact that one may have just been + // opened. + GetMenuManager(project).UpdateMenus(project, false); + } + + } ); + + int count = 0; + bool clean = true; + for (auto t : tracks->Selected< const WaveTrack >()) { + if (t->GetEndTime() != 0.0) + clean = false; + count++; + } + + EffectManager & em = EffectManager::Get(); + + success = em.DoEffect(ID, &project, rate, + tracks, trackFactory, &selectedRegion, + (flags & MenuCommandHandler::OnEffectFlags::kConfigured) == 0); + + if (!success) + return false; + + if (em.GetSkipStateFlag()) + flags = flags | MenuCommandHandler::OnEffectFlags::kSkipState; + + if (!(flags & MenuCommandHandler::OnEffectFlags::kSkipState)) + { + wxString shortDesc = em.GetCommandName(ID); + wxString longDesc = em.GetCommandDescription(ID); + project.PushState(longDesc, shortDesc); + } + + if (!(flags & MenuCommandHandler::OnEffectFlags::kDontRepeatLast)) + { + // Only remember a successful effect, don't remember insert, + // or analyze effects. + if (type == EffectTypeProcess) { + wxString shortDesc = em.GetCommandName(ID); + GetMenuManager(project).mLastEffect = ID; + wxString lastEffectDesc; + /* i18n-hint: %s will be the name of the effect which will be + * repeated if this menu item is chosen */ + lastEffectDesc.Printf(_("Repeat %s"), shortDesc); + commandManager->Modify(wxT("RepeatLastEffect"), lastEffectDesc); + } + } + + //STM: + //The following automatically re-zooms after sound was generated. + // IMO, it was disorienting, removing to try out without re-fitting + //mchinen:12/14/08 reapplying for generate effects + if (type == EffectTypeGenerate) + { + if (count == 0 || (clean && selectedRegion.t0() == 0.0)) + ViewActions::DoZoomFit(project); + // trackPanel->Refresh(false); + } + project.RedrawProject(); + if (focus != nullptr && focus->GetParent()==parent) { + focus->SetFocus(); + } + + // A fix for Bug 63 + // New tracks added? Scroll them into view so that user sees them. + // Don't care what track type. An analyser might just have added a + // Label track and we want to see it. + if( project.GetTrackCount() > nTracksOriginally ){ + // 0.0 is min scroll position, 1.0 is max scroll position. + trackPanel->VerticalScroll( 1.0 ); + } else { + trackPanel->EnsureVisible(trackPanel->GetFirstSelectedTrack()); + trackPanel->Refresh(false); + } + + return true; +} + +/// DoAudacityCommand() takes a PluginID and executes the assocated command. +/// +/// At the moment flags are used only to indicate whether to prompt for +/// parameters +bool DoAudacityCommand( + const PluginID & ID, const CommandContext & context, unsigned flags ) +{ + auto &project = context.project; + const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID); + if (!plug) + return false; + + if (flags & MenuCommandHandler::OnEffectFlags::kConfigured) + { + TransportActions::DoStop(project); +// SelectAllIfNone(); + } + + EffectManager & em = EffectManager::Get(); + bool success = em.DoAudacityCommand(ID, + context, + &project, + (flags & MenuCommandHandler::OnEffectFlags::kConfigured) == 0); + + if (!success) + return false; + +/* + if (em.GetSkipStateFlag()) + flags = flags | OnEffectFlags::kSkipState; + + if (!(flags & OnEffectFlags::kSkipState)) + { + wxString shortDesc = em.GetCommandName(ID); + wxString longDesc = em.GetCommandDescription(ID); + PushState(longDesc, shortDesc); + } +*/ + project.RedrawProject(); + return true; +} + +// Menu handler functions + +struct Handler : CommandHandlerObject { + +void OnManageGenerators(const CommandContext &context) +{ + auto &project = context.project; + DoManagePluginsMenu(project, EffectTypeGenerate); +} + +void OnEffect(const CommandContext &context) +{ + DoEffect(context.parameter, context, 0); +} + +void OnManageEffects(const CommandContext &context) +{ + auto &project = context.project; + DoManagePluginsMenu(project, EffectTypeProcess); +} + +void OnRepeatLastEffect(const CommandContext &context) +{ + auto lastEffect = GetMenuManager(context.project).mLastEffect; + if (!lastEffect.IsEmpty()) + { + DoEffect(lastEffect, + context, MenuCommandHandler::OnEffectFlags::kConfigured); + } +} + +void OnManageAnalyzers(const CommandContext &context) +{ + auto &project = context.project; + DoManagePluginsMenu(project, EffectTypeAnalyze); +} + +void OnContrast(const CommandContext &context) +{ + auto &project = context.project; + auto contrastDialog = project.GetContrastDialog(true); + + + contrastDialog->CentreOnParent(); + if( ScreenshotCommand::MayCapture( contrastDialog ) ) + return; + contrastDialog->Show(); +} + +void OnPlotSpectrum(const CommandContext &context) +{ + auto &project = context.project; + auto freqWindow = project.GetFreqWindow(true); + + + if( ScreenshotCommand::MayCapture( freqWindow ) ) + return; + freqWindow->Show(true); + freqWindow->Raise(); + freqWindow->SetFocus(); +} + +void OnManageTools(const CommandContext &context ) +{ + auto &project = context.project; + DoManagePluginsMenu(project, EffectTypeTool); +} + +void OnManageMacros(const CommandContext &context ) +{ + auto &project = context.project; + project.GetMacrosWindow( true, true ); +} + +void OnApplyMacrosPalette(const CommandContext &context ) +{ + auto &project = context.project; + project.GetMacrosWindow( false, true ); +} + +void OnScreenshot(const CommandContext &WXUNUSED(context) ) +{ + ::OpenScreenshotTools(); +} + +void OnBenchmark(const CommandContext &context) +{ + auto &project = context.project; + ::RunBenchmark(&project); +} + +void OnSimulateRecordingErrors(const CommandContext &context) +{ + auto &project = context.project; + auto commandManager = project.GetCommandManager(); + + bool &setting = gAudioIO->mSimulateRecordingErrors; + commandManager->Check(wxT("SimulateRecordingErrors"), !setting); + setting = !setting; +} + +void OnDetectUpstreamDropouts(const CommandContext &context) +{ + auto &project = context.project; + auto commandManager = project.GetCommandManager(); + + bool &setting = gAudioIO->mDetectUpstreamDropouts; + commandManager->Check(wxT("DetectUpstreamDropouts"), !setting); + setting = !setting; +} + +void OnApplyMacroDirectly(const CommandContext &context ) +{ + auto &project = context.project; + + //wxLogDebug( "Macro was: %s", context.parameter); + ApplyMacroDialog dlg( &project ); + wxString Name = context.parameter; + +// We used numbers previously, but macros could get renumbered, making +// macros containing macros unpredictable. +#ifdef MACROS_BY_NUMBERS + long item=0; + // Take last three letters (of e.g. Macro007) and convert to a number. + Name.Mid( Name.Length() - 3 ).ToLong( &item, 10 ); + dlg.ApplyMacroToProject( item, false ); +#else + dlg.ApplyMacroToProject( Name, false ); +#endif + MenuManager::ModifyUndoMenuItems( project ); +} + +void OnAudacityCommand(const CommandContext & ctx) +{ + wxLogDebug( "Command was: %s", ctx.parameter); + // Not configured, so prompt user. + DoAudacityCommand(EffectManager::Get().GetEffectByIdentifier(ctx.parameter), + ctx, + MenuCommandHandler::OnEffectFlags::kNone); +} + +}; // struct Handler + +} // namespace + +static CommandHandlerObject &findCommandHandler(AudacityProject &) { + // Handler is not stateful. Doesn't need a factory registered with + // AudacityProject. + static PluginActions::Handler instance; + return instance; +}; + +// Menu definitions? ... + +#define FN(X) findCommandHandler, \ + static_cast(& PluginActions::Handler :: X) +#define XXO(X) _(X), wxString{X}.Contains("...") + +// ... buf first some more helper definitions, which use FN +namespace { + +void AddEffectMenuItemGroup( + MenuTable::BaseItemPtrs &table, + const wxArrayString & names, + const std::vector &vHasDialog, + const PluginIDList & plugs, + const std::vector & flags, + bool isDefault) +{ + const int namesCnt = (int) names.GetCount(); + int perGroup; + +#if defined(__WXGTK__) + gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 15); +#else + gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 0); +#endif + + int groupCnt = namesCnt; + for (int i = 0; i < namesCnt; i++) + { + while (i + 1 < namesCnt && names[i].IsSameAs(names[i + 1])) + { + i++; + groupCnt--; + } + } + + // The "default" effects shouldn't be broken into subgroups + if (namesCnt > 0 && isDefault) + { + perGroup = 0; + } + + int max = perGroup; + int items = perGroup; + + if (max > groupCnt) + { + max = 0; + } + + using namespace MenuTable; + auto pTable = &table; + BaseItemPtrs temp1; + + int groupNdx = 0; + for (int i = 0; i < namesCnt; i++) + { + if (max > 0 && items == max) + { + // start collecting items for the next submenu + pTable = &temp1; + } + + if (i + 1 < namesCnt && names[i].IsSameAs(names[i + 1])) + { + // collect a sub-menu for like-named items + const wxString name = names[i]; + BaseItemPtrs temp2; + while (i < namesCnt && names[i].IsSameAs(name)) + { + const PluginDescriptor *plug = + PluginManager::Get().GetPlugin(plugs[i]); + wxString item = plug->GetPath(); + if( plug->GetPluginType() == PluginTypeEffect ) + temp2.push_back( Command( item, + item, + item.Contains("..."), + FN(OnEffect), + flags[i], + CommandManager::Options{} + .IsEffect().Parameter( plugs[i] ) ) ); + + i++; + } + pTable->push_back( Menu( name, std::move( temp2 ) ) ); + i--; + } + else + { + // collect one item + const PluginDescriptor *plug = + PluginManager::Get().GetPlugin(plugs[i]); + if( plug->GetPluginType() == PluginTypeEffect ) + pTable->push_back( Command( names[i], + names[i], + vHasDialog[i], + FN(OnEffect), + flags[i], + CommandManager::Options{} + .IsEffect().Parameter( plugs[i] ) ) ); + } + + if (max > 0) + { + items--; + if (items == 0 || i + 1 == namesCnt) + { + int end = groupNdx + max; + if (end + 1 > groupCnt) + { + end = groupCnt; + } + // Done collecting + table.push_back( Menu( + wxString::Format(_("Plug-in %d to %d"), groupNdx + 1, end), + std::move( temp1 ) + ) ); + items = max; + pTable = &table; + } + groupNdx++; + } + } + + return; +} + +MenuTable::BaseItemPtrs PopulateMacrosMenu( CommandFlag flags ) +{ + MenuTable::BaseItemPtrs result; + wxArrayString names = MacroCommands::GetNames(); + int i; + + for (i = 0; i < (int)names.GetCount(); i++) { + wxString MacroID = ApplyMacroDialog::MacroIdOfName( names[i] ); + result.push_back( MenuTable::Command( MacroID, + names[i], false, FN(OnApplyMacroDirectly), + flags ) ); + } + + return result; +} + +} + +// Menu definitions + +MenuTable::BaseItemPtr GenerateMenu( AudacityProject & ) +{ + using namespace MenuTable; + // All of this is a bit hacky until we can get more things connected into + // the plugin manager...sorry! :-( + + return Menu( _("&Generate"), +#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT + Command( wxT("ManageGenerators"), XXO("Add / Remove Plug-ins..."), + FN(OnManageGenerators), AudioIONotBusyFlag ), + + Separator(), + +#endif + + Items( PopulateEffectsMenu( + EffectTypeGenerate, + AudioIONotBusyFlag, + AudioIONotBusyFlag) ) + ); +} + +MenuTable::BaseItemPtr EffectMenu( AudacityProject &project ) +{ + using namespace MenuTable; + // All of this is a bit hacky until we can get more things connected into + // the plugin manager...sorry! :-( + + const auto &lastEffect = GetMenuManager(project).mLastEffect; + wxString buildMenuLabel; + if (!lastEffect.IsEmpty()) { + buildMenuLabel.Printf(_("Repeat %s"), + EffectManager::Get().GetCommandName(lastEffect)); + } + else + buildMenuLabel = _("Repeat Last Effect"); + + return Menu( _("Effe&ct"), +#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT + Command( wxT("ManageEffects"), XXO("Add / Remove Plug-ins..."), + FN(OnManageEffects), AudioIONotBusyFlag ), + + Separator(), + +#endif + Command( wxT("RepeatLastEffect"), buildMenuLabel, false, + FN(OnRepeatLastEffect), + AudioIONotBusyFlag | TimeSelectedFlag | + WaveTracksSelectedFlag | HasLastEffectFlag, + wxT("Ctrl+R") ), + + Separator(), + + Items( PopulateEffectsMenu( + EffectTypeProcess, + AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, + IsRealtimeNotActiveFlag ) ) + ); +} + +MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject & ) +{ + using namespace MenuTable; + // All of this is a bit hacky until we can get more things connected into + // the plugin manager...sorry! :-( + + return Menu( _("&Analyze"), +#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT + Command( wxT("ManageAnalyzers"), XXO("Add / Remove Plug-ins..."), + FN(OnManageAnalyzers), AudioIONotBusyFlag ), + + Separator(), + +#endif + + Command( wxT("ContrastAnalyser"), XXO("Contrast..."), FN(OnContrast), + AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag, + wxT("Ctrl+Shift+T") ), + Command( wxT("PlotSpectrum"), XXO("Plot Spectrum..."), FN(OnPlotSpectrum), + AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag ), + + Items( PopulateEffectsMenu( + EffectTypeAnalyze, + AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag, + IsRealtimeNotActiveFlag ) ) + ); +} + +MenuTable::BaseItemPtr ToolsMenu( AudacityProject & ) +{ + using namespace MenuTable; + using Options = CommandManager::Options; + + return Menu( _("T&ools"), + +#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT + Command( wxT("ManageTools"), XXO("Add / Remove Plug-ins..."), + FN(OnManageTools), AudioIONotBusyFlag ), + + //Separator(), + +#endif + + Command( wxT("ManageMacros"), XXO("&Macros..."), + FN(OnManageMacros), AudioIONotBusyFlag ), + + Menu( _("&Apply Macro"), + // Palette has no access key to ensure first letter navigation of + // sub menu + Command( wxT("ApplyMacrosPalette"), XXO("Palette..."), + FN(OnApplyMacrosPalette), AudioIONotBusyFlag ), + + Separator(), + + Items( PopulateMacrosMenu( AudioIONotBusyFlag ) ) + ), + + Separator(), + + Command( wxT("FancyScreenshot"), XXO("&Screenshot..."), + FN(OnScreenshot), AudioIONotBusyFlag ), + +// PRL: team consensus for 2.2.0 was, we let end users have this diagnostic, +// as they used to in 1.3.x +//#ifdef IS_ALPHA + // TODO: What should we do here? Make benchmark a plug-in? + // Easy enough to do. We'd call it mod-self-test. + Command( wxT("Benchmark"), XXO("&Run Benchmark..."), + FN(OnBenchmark), AudioIONotBusyFlag ), +//#endif + + Separator(), + + Items( PopulateEffectsMenu( + EffectTypeTool, + AudioIONotBusyFlag, + AudioIONotBusyFlag ) ) + +#ifdef IS_ALPHA + , + + Separator(), + + Command( wxT("SimulateRecordingErrors"), + XXO("Simulate Recording Errors"), + FN(OnSimulateRecordingErrors), + AudioIONotBusyFlag, + Options{}.CheckState( gAudioIO->mSimulateRecordingErrors ) ), + Command( wxT("DetectUpstreamDropouts"), + XXO("Detect Upstream Dropouts"), + FN(OnDetectUpstreamDropouts), + AudioIONotBusyFlag, + Options{}.CheckState( gAudioIO->mDetectUpstreamDropouts ) ) +#endif + ); +} + +MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & ) +{ + using namespace MenuTable; + + // These are the more useful to VI user Scriptables. + // i18n-hint: Scriptables are commands normally used from Python, Perl etc. + return Menu( _("Script&ables I"), + // Note that the PLUGIN_SYMBOL must have a space between words, + // whereas the short-form used here must not. + // (So if you did write "CompareAudio" for the PLUGIN_SYMBOL name, then + // you would have to use "Compareaudio" here.) + Command( wxT("SelectTime"), XXO("Select Time..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SelectFrequencies"), XXO("Select Frequencies..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SelectTracks"), XXO("Select Tracks..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetTrackStatus"), XXO("Set Track Status..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetTrackAudio"), XXO("Set Track Audio..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetTrackVisuals"), XXO("Set Track Visuals..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("GetPreference"), XXO("Get Preference..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetPreference"), XXO("Set Preference..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetClip"), XXO("Set Clip..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetEnvelope"), XXO("Set Envelope..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetLabel"), XXO("Set Label..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetProject"), XXO("Set Project..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ) + ); +} + +MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & ) +{ + using namespace MenuTable; + + // Less useful to VI users. + return Menu( _("Scripta&bles II"), + Command( wxT("Select"), XXO("Select..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SetTrack"), XXO("Set Track..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("GetInfo"), XXO("Get Info..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("Message"), XXO("Message..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("Help"), XXO("Help..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("Import2"), XXO("Import..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("Export2"), XXO("Export..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("OpenProject2"), XXO("Open Project..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("SaveProject2"), XXO("Save Project..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("Drag"), XXO("Move Mouse..."), FN(OnAudacityCommand), + AudioIONotBusyFlag ), + Command( wxT("CompareAudio"), XXO("Compare Audio..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ), + // i18n-hint: Screenshot in the help menu has a much bigger dialog. + Command( wxT("Screenshot"), XXO("Screenshot (short format)..."), + FN(OnAudacityCommand), + AudioIONotBusyFlag ) + ); +} + +#undef XXO +#undef FN diff --git a/src/menus/TrackMenus.cpp b/src/menus/TrackMenus.cpp index d5d62c3e0..c81519c52 100644 --- a/src/menus/TrackMenus.cpp +++ b/src/menus/TrackMenus.cpp @@ -635,8 +635,8 @@ void OnNewTimeTrack(const CommandContext &context) void OnStereoToMono(const CommandContext &context) { - GetMenuCommandHandler(context.project). - DoEffect(EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono")), + PluginActions::DoEffect( + EffectManager::Get().GetEffectByIdentifier(wxT("StereoToMono")), context, MenuCommandHandler::OnEffectFlags::kConfigured); }