mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-22 06:22:58 +02:00
Automation: AudacityCommand
This is a squash of 50 commits. This merges the capabilities of BatchCommands and Effects using a new AudacityCommand class. AudacityCommand provides one function to specify the parameters, and then we leverage that one function in automation, whether by chains, mod-script-pipe or (future) Nyquist. - Now have AudacityCommand which is using the same mechanism as Effect - Has configurable parameters - Has data-entry GUI (built using shuttle GUI) - Registers with PluginManager. - Menu commands now provided in chains, and to python batch. - Tested with Zoom Toggle. - ShuttleParams now can set, get, set defaults, validate and specify the parameters. - Bugfix: Don't overwrite values with defaults first time out. - Add DefineParams function for all built-in effects. - Extend CommandContext to carry output channels for results. We abuse EffectsManager. It handles both Effects and AudacityCommands now. In time an Effect should become a special case of AudacityCommand and we'll split and rename the EffectManager class. - Don't use 'default' as a parameter name. - Massive renaming for CommandDefinitionInterface - EffectIdentInterface becomes EffectDefinitionInterface - EffectAutomationParameters becomes CommandAutomationParameters - PluginType is now a bit field. This way we can search for related types at the same time. - Most old batch commands made into AudacityCommands. The ones that weren't are for a reason. They are used by mod-script-pipe to carry commands and responses across from a non-GUI thread to the GUI thread. - Major tidy up of ScreenshotCommand - Reworking of SelectCommand - GetPreferenceCommand and SetPreferenceCommand - GetTrackInfo and SetTrackInfo - GetInfoCommand - Help, Open, Save, Import and Export commands. - Removed obsolete commands ExecMenu, GetProjectInfo and SetProjectInfo which are now better handled by other commands. - JSONify "GetInfo: Commands" output, i.e. commas in the right places. - General work on better Doxygen. - Lyrics -> LyricsPanel - Meter -> MeterPanel - Updated Linux makefile. - Scripting commands added into Extra menu. - Distinct names for previously duplicated find-clipping parameters. - Fixed longstanding error with erroneous status field number which previously caused an ASSERT in debug. - Sensible formatting of numbers in Chains, 0.1 not 0.1000000000137
This commit is contained in:
committed by
Paul Licameli
parent
b7b01d48e0
commit
1c988b4e3a
342
src/commands/AudacityCommand.cpp
Normal file
342
src/commands/AudacityCommand.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
AudacityCommand.cpp
|
||||
|
||||
James Crook
|
||||
|
||||
*******************************************************************//**
|
||||
|
||||
\class AudacityCommand
|
||||
\brief Base class for command in Audacity.
|
||||
|
||||
*//****************************************************************//**
|
||||
|
||||
\class AudacityCommandDialog
|
||||
\brief Default dialog used for commands. Is populated using
|
||||
ShuttleGui.
|
||||
|
||||
*//*******************************************************************/
|
||||
|
||||
#include "../Audacity.h"
|
||||
#include "AudacityCommand.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/hashmap.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stockitem.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/tglbtn.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "audacity/ConfigInterface.h"
|
||||
|
||||
#include "../AudacityException.h"
|
||||
#include "../AudioIO.h"
|
||||
#include "../LabelTrack.h"
|
||||
#include "../Mix.h"
|
||||
#include "../Prefs.h"
|
||||
#include "../Project.h"
|
||||
#include "../ShuttleGui.h"
|
||||
#include "../WaveTrack.h"
|
||||
#include "../toolbars/ControlToolBar.h"
|
||||
#include "../widgets/AButton.h"
|
||||
#include "../widgets/ProgressDialog.h"
|
||||
#include "../ondemand/ODManager.h"
|
||||
#include "../widgets/HelpSystem.h"
|
||||
#include "../widgets/LinkingHtmlWindow.h"
|
||||
#include "../widgets/ErrorDialog.h"
|
||||
#include "../FileNames.h"
|
||||
|
||||
#include "../commands/CommandTargets.h"
|
||||
|
||||
#include "../Experimental.h"
|
||||
#include "../commands/ScreenshotCommand.h"
|
||||
|
||||
#ifndef __AUDACITY_OLD_STD__
|
||||
#include <unordered_map>
|
||||
#endif
|
||||
#include "../commands/CommandContext.h"
|
||||
|
||||
AudacityCommand::AudacityCommand()
|
||||
{
|
||||
mProgress = NULL;
|
||||
mUIParent = NULL;
|
||||
mUIDialog = NULL;
|
||||
mUIDebug = false;
|
||||
mIsBatch = false;
|
||||
mNeedsInit = true;
|
||||
}
|
||||
|
||||
AudacityCommand::~AudacityCommand()
|
||||
{
|
||||
if (mUIDialog)
|
||||
mUIDialog->Close();
|
||||
}
|
||||
|
||||
|
||||
wxString AudacityCommand::GetPath(){ return BUILTIN_GENERIC_COMMAND_PREFIX + GetSymbol();}
|
||||
wxString AudacityCommand::GetName(){ return GetSymbol();}
|
||||
wxString AudacityCommand::GetVendor(){ return XO("Audacity");}
|
||||
wxString AudacityCommand::GetVersion(){ return AUDACITY_VERSION_STRING;}
|
||||
|
||||
|
||||
bool AudacityCommand::Apply() {
|
||||
AudacityProject * pProj = GetActiveProject();
|
||||
const CommandContext context( *pProj );
|
||||
return Apply( context );
|
||||
};
|
||||
|
||||
bool AudacityCommand::Init(){
|
||||
if( !mNeedsInit )
|
||||
return true;
|
||||
mNeedsInit = false;
|
||||
ShuttleDefaults DefaultSettingShuttle;
|
||||
return DefineParams( DefaultSettingShuttle );
|
||||
}
|
||||
|
||||
bool AudacityCommand::ShowInterface(wxWindow *parent, bool WXUNUSED(forceModal))
|
||||
{
|
||||
if (mUIDialog)
|
||||
{
|
||||
if ( mUIDialog->Close(true) )
|
||||
mUIDialog = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// mUIDialog is null
|
||||
auto cleanup = valueRestorer( mUIDialog );
|
||||
|
||||
mUIDialog = CreateUI(parent, this);
|
||||
if (!mUIDialog)
|
||||
return false;
|
||||
|
||||
mUIDialog->Layout();
|
||||
mUIDialog->Fit();
|
||||
mUIDialog->SetMinSize(mUIDialog->GetSize());
|
||||
|
||||
// The Screenshot command might be popping this dialog up, just to capture it.
|
||||
if( ScreenshotCommand::MayCapture( mUIDialog ) )
|
||||
return false;
|
||||
|
||||
bool res = mUIDialog->ShowModal() != 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
wxDialog *AudacityCommand::CreateUI(wxWindow *parent, AudacityCommand * WXUNUSED(client))
|
||||
{
|
||||
Destroy_ptr<AudacityCommandDialog> dlg { safenew AudacityCommandDialog{
|
||||
parent, "Generic Dialog", this}};
|
||||
|
||||
if (dlg->Init())
|
||||
{
|
||||
// release() is safe because parent will own it
|
||||
return dlg.release();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool AudacityCommand::GetAutomationParameters(wxString & parms)
|
||||
{
|
||||
CommandAutomationParameters eap;
|
||||
|
||||
if (mUIDialog && !TransferDataFromWindow())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ShuttleGetAutomation S;
|
||||
S.mpEap = &eap;
|
||||
bool bResult = DefineParams( S );
|
||||
wxASSERT_MSG( bResult, "You did not define DefineParameters() for this command" );
|
||||
|
||||
return eap.GetParameters(parms);
|
||||
}
|
||||
|
||||
bool AudacityCommand::SetAutomationParameters(const wxString & parms)
|
||||
{
|
||||
wxString preset = parms;
|
||||
|
||||
CommandAutomationParameters eap(parms);
|
||||
ShuttleSetAutomation S;
|
||||
|
||||
S.SetForWriting( &eap );
|
||||
bool bResult = DefineParams( S );
|
||||
wxASSERT_MSG( bResult, "You did not define DefineParameters() for this command" );
|
||||
if (!S.bOK)
|
||||
{
|
||||
AudacityCommand::MessageBox(
|
||||
wxString::Format(
|
||||
_("%s: Could not load settings below. Default settings will be used.\n\n%s"),
|
||||
GetTranslatedName(),
|
||||
preset
|
||||
)
|
||||
);
|
||||
|
||||
// fror now always succeed, so that we can prompt the user.
|
||||
return true;
|
||||
}
|
||||
|
||||
return TransferDataToWindow();
|
||||
}
|
||||
|
||||
bool AudacityCommand::DoAudacityCommand(wxWindow *parent,
|
||||
const CommandContext & context,
|
||||
bool shouldPrompt /* = true */)
|
||||
{
|
||||
// Note: Init may read parameters from preferences
|
||||
if (!Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prompting will be bypassed when applying a command that has already
|
||||
// been configured, e.g. repeating the last effect on a different selection.
|
||||
// Prompting may call AudacityCommand::Preview
|
||||
if (shouldPrompt && /*IsInteractive() && */!PromptUser(parent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cleanup = finally( [&] {
|
||||
End();
|
||||
} );
|
||||
|
||||
bool returnVal = true;
|
||||
bool skipFlag = CheckWhetherSkipAudacityCommand();
|
||||
if (skipFlag == false)
|
||||
{
|
||||
auto name = GetTranslatedName();
|
||||
ProgressDialog progress{
|
||||
name,
|
||||
wxString::Format(_("Applying %s..."), name),
|
||||
pdlgHideStopButton
|
||||
};
|
||||
auto vr = valueRestorer( mProgress, &progress );
|
||||
|
||||
returnVal = Apply(context);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
// This is used from Chains.
|
||||
bool AudacityCommand::PromptUser(wxWindow *parent)
|
||||
{
|
||||
return ShowInterface(parent, IsBatchProcessing());
|
||||
}
|
||||
|
||||
bool AudacityCommand::TransferDataToWindow()
|
||||
{
|
||||
if (mUIParent && !mUIParent->TransferDataToWindow())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudacityCommand::TransferDataFromWindow()
|
||||
{
|
||||
if (mUIParent && (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int AudacityCommand::MessageBox(const wxString& message, long style, const wxString &titleStr)
|
||||
{
|
||||
wxString title;
|
||||
if (titleStr.empty())
|
||||
title = GetTranslatedName();
|
||||
else
|
||||
title = wxString::Format(_("%s: %s"), GetTranslatedName(), titleStr);
|
||||
return AudacityMessageBox(message, title, style, mUIParent);
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(AudacityCommandDialog, wxDialogWrapper)
|
||||
EVT_BUTTON(wxID_OK, AudacityCommandDialog::OnOk)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
AudacityCommandDialog::AudacityCommandDialog(wxWindow * parent,
|
||||
const wxString & title,
|
||||
AudacityCommand * pCommand,
|
||||
int type,
|
||||
int flags,
|
||||
int additionalButtons)
|
||||
: wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags)
|
||||
{
|
||||
mType = type;
|
||||
wxASSERT( pCommand );
|
||||
mpCommand = pCommand;
|
||||
mAdditionalButtons = additionalButtons;
|
||||
}
|
||||
|
||||
bool AudacityCommandDialog::Init()
|
||||
{
|
||||
ShuttleGui S(this, eIsCreating);
|
||||
|
||||
S.SetBorder(5);
|
||||
S.StartVerticalLay(true);
|
||||
{
|
||||
PopulateOrExchange(S);
|
||||
|
||||
long buttons = eOkButton;
|
||||
S.AddStandardButtons(buttons|mAdditionalButtons);
|
||||
}
|
||||
S.EndVerticalLay();
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
SetMinSize(GetSize());
|
||||
Center();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This is a virtual function which will be overridden to
|
||||
/// provide the actual parameters that we want for each
|
||||
/// kind of dialog.
|
||||
void AudacityCommandDialog::PopulateOrExchange(ShuttleGui & S)
|
||||
{
|
||||
wxASSERT( mpCommand );
|
||||
mpCommand->PopulateOrExchange( S );
|
||||
}
|
||||
|
||||
bool AudacityCommandDialog::TransferDataToWindow()
|
||||
{
|
||||
ShuttleGui S(this, eIsSettingToDialog);
|
||||
PopulateOrExchange(S);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudacityCommandDialog::TransferDataFromWindow()
|
||||
{
|
||||
ShuttleGui S(this, eIsGettingFromDialog);
|
||||
PopulateOrExchange(S);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudacityCommandDialog::Validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudacityCommandDialog::OnOk(wxCommandEvent & WXUNUSED(evt))
|
||||
{
|
||||
// On wxGTK (wx2.8.12), the default action is still executed even if
|
||||
// the button is disabled. This appears to affect all wxDialogs, not
|
||||
// just our AudacityCommands dialogs. So, this is a only temporary workaround
|
||||
// for legacy effects that disable the OK button. Hopefully this has
|
||||
// been corrected in wx3.
|
||||
if (FindWindow(wxID_OK)->IsEnabled() && Validate() && TransferDataFromWindow())
|
||||
{
|
||||
EndModal(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AudacityCommandDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
|
||||
{
|
||||
EndModal(false);
|
||||
}
|
||||
|
Reference in New Issue
Block a user