diff --git a/src/CommonCommandFlags.cpp b/src/CommonCommandFlags.cpp index 3e2b4edd4..b65676bd5 100644 --- a/src/CommonCommandFlags.cpp +++ b/src/CommonCommandFlags.cpp @@ -253,6 +253,7 @@ const ReservedCommandFlag& const ReservedCommandFlag& HasLastAnalyzerFlag() { static ReservedCommandFlag flag{ [](const AudacityProject &project) { + if (MenuManager::Get(project).mLastAnalyzerRegistration == MenuCreator::repeattypeunique) return true; return !MenuManager::Get(project).mLastAnalyzer.empty(); } }; return flag; @@ -260,7 +261,9 @@ const ReservedCommandFlag& const ReservedCommandFlag& HasLastToolFlag() { static ReservedCommandFlag flag{ [](const AudacityProject &project) { - return !MenuManager::Get(project).mLastTool.empty(); + auto& menuManager = MenuManager::Get(project); + if (menuManager.mLastToolRegistration == MenuCreator::repeattypeunique) return true; + return !menuManager.mLastTool.empty(); } }; return flag; } diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp index d06058e4e..f8c1479e1 100644 --- a/src/FreqWindow.cpp +++ b/src/FreqWindow.cpp @@ -1160,6 +1160,7 @@ struct Handler : CommandHandlerObject { void OnPlotSpectrum(const CommandContext &context) { auto &project = context.project; + CommandManager::Get(project).RegisterLastAnalyzer(context); //Register Plot Spectrum as Last Analyzer auto freqWindow = &project.AttachedWindows::Get< FrequencyPlotDialog >( sFrequencyWindowKey ); diff --git a/src/Menus.cpp b/src/Menus.cpp index 5c4166714..0594a3498 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -48,6 +48,8 @@ MenuCreator::MenuCreator() { + mLastAnalyzerRegistration = repeattypenone; + mLastToolRegistration = repeattypenone; } MenuCreator::~MenuCreator() diff --git a/src/Menus.h b/src/Menus.h index 932f31cdd..e758b4618 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -52,8 +52,21 @@ public: PluginID mLastGenerator{}; PluginID mLastEffect{}; PluginID mLastAnalyzer{}; + int mLastAnalyzerRegistration; + int mLastAnalyzerRegisteredId; PluginID mLastTool{}; - bool mLastToolIsMacro; + int mLastToolRegistration; + int mLastToolRegisteredId; + enum { + repeattypenone = 0, + repeattypeplugin = 1, + repeattypeunique = 2, + repeattypeapplymacro = 3 + }; + unsigned mRepeatGeneratorFlags; + unsigned mRepeatEffectFlags; + unsigned mRepeatAnalyzerFlags; + unsigned mRepeatToolFlags; }; struct ToolbarMenuVisitor; diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 5bd1df873..e459cff63 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -235,6 +235,7 @@ CommandManager::CommandManager(): { mbSeparatorAllowed = false; SetMaxList(); + mLastProcessId = 0; } /// @@ -722,23 +723,6 @@ CommandListEntry *CommandManager::NewIdentifier(const CommandID & nameIn, entry->id = wxID_EXIT; else if (name == wxT("About")) entry->id = wxID_ABOUT; - -#if defined(BE_CAREFUL) - // Don't be tempted to do this unless you're willing to change how - // HandleMenuID() decides if a menu action should be performed. - // (see comments 6-9 in bug #2642 for symptoms) - else if (name == wxT("Copy")) - entry->id = wxID_COPY; - else if (name == wxT("Cut")) - entry->id = wxID_CUT; - else if (name == wxT("Delete")) - entry->id = wxID_CLEAR; - else if (name == wxT("Paste")) - entry->id = wxID_PASTE; - else if (name == wxT("SelectAll")) - entry->id = wxID_SELECTALL; -#endif - #endif entry->name = name; @@ -1192,6 +1176,7 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent & return false; } + /// HandleCommandEntry() takes a CommandListEntry and executes it /// returning true iff successful. If you pass any flags, ///the command won't be executed unless the flags are compatible @@ -1219,15 +1204,54 @@ bool CommandManager::HandleCommandEntry(AudacityProject &project, // Otherwise we may get other handlers having a go at obeying the command. if (!allowed) return true; + mNiceName = NiceName; + } + else { + mNiceName = XO(""); } const CommandContext context{ project, evt, entry->index, entry->parameter }; auto &handler = entry->finder(project); (handler.*(entry->callback))(context); - + mLastProcessId = 0; return true; } +// Called by Contrast and Plot Spectrum Plug-ins to mark them as Last Analzers. +// Note that Repeat data has previously been collected +void CommandManager::RegisterLastAnalyzer(const CommandContext& context) { + if (mLastProcessId != 0) { + auto& menuManager = MenuManager::Get(context.project); + menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypeunique; + menuManager.mLastAnalyzerRegisteredId = mLastProcessId; + auto lastEffectDesc = XO("Repeat %s").Format(mNiceName); + Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc); + } + return; +} + +// Called by Selected Tools to mark them as Last Tools. +// Note that Repeat data has previously been collected +void CommandManager::RegisterLastTool(const CommandContext& context) { + if (mLastProcessId != 0) { + auto& menuManager = MenuManager::Get(context.project); + menuManager.mLastToolRegistration = MenuCreator::repeattypeunique; + menuManager.mLastToolRegisteredId = mLastProcessId; + auto lastEffectDesc = XO("Repeat %s").Format(mNiceName); + Modify(wxT("RepeatLastTool"), lastEffectDesc); + } + return; +} + +// Used to invoke Repeat Last Analyzer Process for built-in, non-nyquist plug-ins. +void CommandManager::DoRepeatProcess(const CommandContext& context, int id) { + mLastProcessId = 0; //Don't Process this as repeat + CommandListEntry* entry = mCommandNumericIDHash[id]; + auto& handler = entry->finder(context.project); + (handler.*(entry->callback))(context); +} + + ///Call this when a menu event is received. ///If it matches a command, it will call the appropriate ///CommandManagerListener function. If you pass any flags, @@ -1236,6 +1260,7 @@ bool CommandManager::HandleCommandEntry(AudacityProject &project, bool CommandManager::HandleMenuID( AudacityProject &project, int id, CommandFlag flags, bool alwaysEnabled) { + mLastProcessId = id; CommandListEntry *entry = mCommandNumericIDHash[id]; auto hook = sMenuHook(); diff --git a/src/commands/CommandManager.h b/src/commands/CommandManager.h index 11f12b33a..c380c01bc 100644 --- a/src/commands/CommandManager.h +++ b/src/commands/CommandManager.h @@ -209,6 +209,9 @@ class AUDACITY_DLL_API CommandManager final // Lyrics and MixerTrackCluster classes use it. bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit = false); bool HandleMenuID(AudacityProject &project, int id, CommandFlag flags, bool alwaysEnabled); + void RegisterLastAnalyzer(const CommandContext& context); + void RegisterLastTool(const CommandContext& context); + void DoRepeatProcess(const CommandContext& context, int); enum TextualCommandResult { CommandFailure, @@ -356,6 +359,8 @@ private: bool mbSeparatorAllowed; // false at the start of a menu and immediately after a separator. TranslatableString mCurrentMenuName; + TranslatableString mNiceName; + int mLastProcessId; std::unique_ptr uCurrentMenu; wxMenu *mCurrentMenu {}; diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp index b2d9390b9..aa472ab5e 100644 --- a/src/effects/Contrast.cpp +++ b/src/effects/Contrast.cpp @@ -672,6 +672,7 @@ struct Handler : CommandHandlerObject { void OnContrast(const CommandContext &context) { auto &project = context.project; + CommandManager::Get(project).RegisterLastAnalyzer(context); //Register Contrast as Last Analyzer auto contrastDialog = &project.AttachedWindows::Get< ContrastDialog >( sContrastDialogKey ); diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 176920653..e5663224e 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -100,6 +100,7 @@ Effect::Effect() mUIParent = NULL; mUIDialog = NULL; + mUIFlags = 0; mNumAudioIn = 0; mNumAudioOut = 0; @@ -1179,6 +1180,14 @@ wxString Effect::HelpPage() return wxEmptyString; } +void Effect::SetUIFlags(unsigned flags) { + mUIFlags = flags; +} + +unsigned Effect::TestUIFlags(unsigned mask) { + return mask & mUIFlags; +} + bool Effect::IsBatchProcessing() { return mIsBatch; diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 54fec8a4d..f23812f2f 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -244,6 +244,8 @@ class AUDACITY_DLL_API Effect /* not final */ : public wxEvtHandler, // Fully qualified local help file name virtual wxString HelpPage(); + virtual void SetUIFlags(unsigned flags); + virtual unsigned TestUIFlags(unsigned mask); virtual bool IsBatchProcessing(); virtual void SetBatchProcessing(bool start); @@ -476,6 +478,7 @@ protected: wxDialog *mUIDialog; wxWindow *mUIParent; int mUIResultID; + unsigned mUIFlags; sampleCount mSampleCnt; diff --git a/src/effects/EffectManager.h b/src/effects/EffectManager.h index 8127b4d32..46caf0d37 100644 --- a/src/effects/EffectManager.h +++ b/src/effects/EffectManager.h @@ -54,11 +54,13 @@ public: // Flag used to disable prompting for configuration parameteres. kConfigured = 0x01, // Flag used to disable saving the state after processing. - kSkipState = 0x02, + kSkipState = 0x02, // Flag used to disable "Repeat Last Effect" kDontRepeatLast = 0x04, // Flag used to disable "Select All during Repeat Generator Effect" kRepeatGen = 0x08, + // Flag used for repeating Nyquist Prompt + kRepeatNyquistPrompt = 0x10, }; /** Get the singleton instance of the EffectManager. Probably not safe diff --git a/src/effects/EffectUI.cpp b/src/effects/EffectUI.cpp index 5febe63f6..c3723ec8e 100644 --- a/src/effects/EffectUI.cpp +++ b/src/effects/EffectUI.cpp @@ -1925,6 +1925,7 @@ wxDialog *EffectUI::DialogFactory( wxWindow &parent, EffectHostInterface *pHost, EffectRack::Get( context.project ).Add(effect); } #endif + effect->SetUIFlags(flags); success = effect->DoEffect( rate, &tracks, @@ -1959,23 +1960,32 @@ wxDialog *EffectUI::DialogFactory( wxWindow &parent, EffectHostInterface *pHost, /* i18n-hint: %s will be the name of the effect which will be * repeated if this menu item is chosen */ auto lastEffectDesc = XO("Repeat %s").Format(shortDesc); + auto& menuManager = MenuManager::Get(project); switch ( type ) { case EffectTypeGenerate: commandManager.Modify(wxT("RepeatLastGenerator"), lastEffectDesc); - MenuManager::Get(project).mLastGenerator = ID; + menuManager.mLastGenerator = ID; + menuManager.mRepeatGeneratorFlags = EffectManager::kConfigured; break; case EffectTypeProcess: commandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc); - MenuManager::Get(project).mLastEffect = ID; + menuManager.mLastEffect = ID; + menuManager.mRepeatEffectFlags = EffectManager::kConfigured; break; case EffectTypeAnalyze: commandManager.Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc); - MenuManager::Get(project).mLastAnalyzer = ID; + menuManager.mLastAnalyzer = ID; + menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypeplugin; + menuManager.mRepeatAnalyzerFlags = EffectManager::kConfigured; break; case EffectTypeTool: commandManager.Modify(wxT("RepeatLastTool"), lastEffectDesc); - MenuManager::Get(project).mLastTool = ID; - MenuManager::Get(project).mLastToolIsMacro = false; + menuManager.mLastTool = ID; + menuManager.mLastToolRegistration = MenuCreator::repeattypeplugin; + menuManager.mRepeatToolFlags = EffectManager::kConfigured; + if (shortDesc == XO("Nyquist Prompt")) { + menuManager.mRepeatToolFlags = EffectManager::kRepeatNyquistPrompt; //Nyquist Prompt is not configured + } break; } } diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index f0a324497..c497e467e 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -1001,8 +1001,12 @@ finish: bool NyquistEffect::ShowInterface( wxWindow &parent, const EffectDialogFactory &factory, bool forceModal) { - // Show the normal (prompt or effect) interface - bool res = Effect::ShowInterface(parent, factory, forceModal); + bool res = true; + if (!(Effect::TestUIFlags(EffectManager::kRepeatNyquistPrompt) && mIsPrompt)) { + // Show the normal (prompt or effect) interface + res = Effect::ShowInterface(parent, factory, forceModal); + } + // Remember if the user clicked debug mDebug = (mUIResultID == eDebugID); diff --git a/src/menus/PluginMenus.cpp b/src/menus/PluginMenus.cpp index 1c9b77470..ab3642ac9 100644 --- a/src/menus/PluginMenus.cpp +++ b/src/menus/PluginMenus.cpp @@ -377,6 +377,14 @@ struct Handler : CommandHandlerObject { void OnResetConfig(const CommandContext &context) { auto &project = context.project; + auto &menuManager = MenuManager::Get(project); + menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypenone; + menuManager.mLastToolRegistration = MenuCreator::repeattypenone; + menuManager.mLastGenerator = ""; + menuManager.mLastEffect = ""; + menuManager.mLastAnalyzer = ""; + menuManager.mLastTool = ""; + gPrefs->DeleteAll(); // Directory will be reset on next restart. @@ -429,46 +437,72 @@ void OnManageEffects(const CommandContext &context) DoManagePluginsMenu(project, EffectTypeProcess); } +void OnAnalyzer2(wxCommandEvent& evt) { return; } + void OnRepeatLastGenerator(const CommandContext &context) { - auto lastEffect = MenuManager::Get(context.project).mLastGenerator; + auto& menuManager = MenuManager::Get(context.project); + auto lastEffect = menuManager.mLastGenerator; if (!lastEffect.empty()) { EffectUI::DoEffect( - lastEffect, context, EffectManager::kConfigured | EffectManager::kRepeatGen); + lastEffect, context, menuManager.mRepeatGeneratorFlags | EffectManager::kRepeatGen); } } void OnRepeatLastEffect(const CommandContext &context) { - auto lastEffect = MenuManager::Get(context.project).mLastEffect; + auto& menuManager = MenuManager::Get(context.project); + auto lastEffect = menuManager.mLastEffect; if (!lastEffect.empty()) { EffectUI::DoEffect( - lastEffect, context, EffectManager::kConfigured); + lastEffect, context, menuManager.mRepeatGeneratorFlags); } } -void OnRepeatLastAnalyzer(const CommandContext &context) +void OnRepeatLastAnalyzer(const CommandContext& context) { - auto lastEffect = MenuManager::Get(context.project).mLastAnalyzer; - if (!lastEffect.empty()) - { - EffectUI::DoEffect( - lastEffect, context, EffectManager::kConfigured); - } -} - -void OnRepeatLastTool(const CommandContext &context) -{ - auto lastEffect = MenuManager::Get(context.project).mLastTool; - if (!lastEffect.empty()) - { - if (!MenuManager::Get(context.project).mLastToolIsMacro) + auto& menuManager = MenuManager::Get(context.project); + switch (menuManager.mLastAnalyzerRegistration) { + case MenuCreator::repeattypeplugin: + { + auto lastEffect = menuManager.mLastAnalyzer; + if (!lastEffect.empty()) + { EffectUI::DoEffect( - lastEffect, context, EffectManager::kConfigured); - else - OnApplyMacroDirectlyByName(context, lastEffect); + lastEffect, context, menuManager.mRepeatAnalyzerFlags); + } + } + break; + case MenuCreator::repeattypeunique: + CommandManager::Get(context.project).DoRepeatProcess(context, + menuManager.mLastAnalyzerRegisteredId); + break; + } +} + +void OnRepeatLastTool(const CommandContext& context) +{ + auto& menuManager = MenuManager::Get(context.project); + switch (menuManager.mLastToolRegistration) { + case MenuCreator::repeattypeplugin: + { + auto lastEffect = menuManager.mLastTool; + if (!lastEffect.empty()) + { + EffectUI::DoEffect( + lastEffect, context, menuManager.mRepeatToolFlags); + } + } + break; + case MenuCreator::repeattypeunique: + CommandManager::Get(context.project).DoRepeatProcess(context, + menuManager.mLastToolRegisteredId); + break; + case MenuCreator::repeattypeapplymacro: + OnApplyMacroDirectlyByName(context, menuManager.mLastTool); + break; } } @@ -488,6 +522,7 @@ void OnManageTools(const CommandContext &context ) void OnManageMacros(const CommandContext &context ) { auto &project = context.project; + CommandManager::Get(project).RegisterLastTool(context); //Register Macros as Last Tool auto macrosWindow = &project.AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey ); if (macrosWindow) { @@ -500,6 +535,7 @@ void OnManageMacros(const CommandContext &context ) void OnApplyMacrosPalette(const CommandContext &context ) { auto &project = context.project; + CommandManager::Get(project).RegisterLastTool(context); //Register Palette as Last Tool auto macrosWindow = &project.AttachedWindows::Get< MacrosWindow >( sMacrosWindowKey ); if (macrosWindow) { @@ -511,12 +547,14 @@ void OnApplyMacrosPalette(const CommandContext &context ) void OnScreenshot(const CommandContext &context ) { + CommandManager::Get(context.project).RegisterLastTool(context); //Register Screenshot as Last Tool ::OpenScreenshotTools( context.project ); } void OnBenchmark(const CommandContext &context) { auto &project = context.project; + CommandManager::Get(project).RegisterLastTool(context); //Register Run Benchmark as Last Tool auto &window = GetProjectFrame( project ); ::RunBenchmark( &window, project); } @@ -570,19 +608,20 @@ void OnApplyMacroDirectlyByName(const CommandContext& context, const MacroID& Na * repeated if this menu item is chosen */ MenuManager::ModifyUndoMenuItems( project ); - TranslatableString desc; - EffectManager& em = EffectManager::Get(); - auto shortDesc = em.GetCommandName(Name); - auto& undoManager = UndoManager::Get(project); - auto& commandManager = CommandManager::Get(project); - int cur = undoManager.GetCurrentState(); - if (undoManager.UndoAvailable()) { - undoManager.GetShortDescription(cur, &desc); - commandManager.Modify(wxT("RepeatLastTool"), XXO("&Repeat %s") - .Format(desc)); - MenuManager::Get(project).mLastTool = Name; - MenuManager::Get(project).mLastToolIsMacro = true; - } + TranslatableString desc; + EffectManager& em = EffectManager::Get(); + auto shortDesc = em.GetCommandName(Name); + auto& undoManager = UndoManager::Get(project); + auto& commandManager = CommandManager::Get(project); + int cur = undoManager.GetCurrentState(); + if (undoManager.UndoAvailable()) { + undoManager.GetShortDescription(cur, &desc); + commandManager.Modify(wxT("RepeatLastTool"), XXO("&Repeat %s") + .Format(desc)); + auto& menuManager = MenuManager::Get(project); + menuManager.mLastTool = Name; + menuManager.mLastToolRegistration = MenuCreator::repeattypeapplymacro; + } }