mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 16:10:06 +02:00
Merge branch 'chains' into master
Some work on chains to make the dialogs easier to use. - Reduced duplications and unnecessary text in the select command dialog. - Select Command Dialog gains a new 'Details' text box. - Resized dialog so that more commands are visible. - Now can apply commands direct from the edit chains dialog. - Editing commands goes direct to editing their parameters. - Fixed minor UI issue where button did nothing if nothing selected.
This commit is contained in:
commit
68e8a75686
@ -95,10 +95,13 @@ void BatchCommandDialog::PopulateOrExchange(ShuttleGui &S)
|
||||
S.SetStretchyCol(1);
|
||||
mParameters = S.AddTextBox(_("&Parameters"), wxT(""), 0);
|
||||
mParameters->SetEditable(false);
|
||||
S.Prop(0).AddPrompt( _("&Details" ) );
|
||||
mDetails = S.AddTextWindow( wxT(""));
|
||||
mDetails->SetEditable(false);
|
||||
}
|
||||
S.EndMultiColumn();
|
||||
|
||||
S.StartStatic(_("C&hoose command"), true);
|
||||
S.Prop(10).StartStatic(_("C&hoose command"), true);
|
||||
{
|
||||
S.SetStyle(wxSUNKEN_BORDER | wxLC_LIST | wxLC_SINGLE_SEL);
|
||||
mChoices = S.Id(CommandsListID).AddListControl();
|
||||
@ -111,7 +114,7 @@ void BatchCommandDialog::PopulateOrExchange(ShuttleGui &S)
|
||||
|
||||
PopulateCommandList();
|
||||
|
||||
SetMinSize(wxSize(500, 400));
|
||||
SetMinSize(wxSize(780, 560));
|
||||
Fit();
|
||||
Center();
|
||||
}
|
||||
@ -123,26 +126,9 @@ void BatchCommandDialog::PopulateCommandList()
|
||||
mChoices->DeleteAllItems();
|
||||
for (size_t ii = 0, size = mCommandNames.size(); ii < size; ++ii)
|
||||
// insert the user-facing string
|
||||
mChoices->InsertItem( ii, mCommandNames[ii].first );
|
||||
mChoices->InsertItem( ii, std::get<0>( mCommandNames[ii] ) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
int BatchCommandDialog::GetSelectedItem()
|
||||
{
|
||||
int i;
|
||||
mSelectedCommand = wxT("");
|
||||
for(i=0;i<mChoices->GetItemCount();i++)
|
||||
{
|
||||
if( mChoices->GetItemState( i, wxLIST_STATE_FOCUSED) != 0)
|
||||
{
|
||||
mSelectedCommand = mChoices->GetItemText( i );
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BatchCommandDialog::ValidateChoices()
|
||||
{
|
||||
}
|
||||
@ -168,25 +154,28 @@ void BatchCommandDialog::OnItemSelected(wxListEvent &event)
|
||||
const auto &command = mCommandNames[ event.GetIndex() ];
|
||||
|
||||
EffectManager & em = EffectManager::Get();
|
||||
PluginID ID = em.GetEffectByIdentifier(command.second);
|
||||
PluginID ID = em.GetEffectByIdentifier( std::get<1>( command ));
|
||||
|
||||
// If ID is empty, then the effect wasn't found, in which case, the user must have
|
||||
// selected one of the "special" commands.
|
||||
mEditParams->Enable(!ID.IsEmpty());
|
||||
mUsePreset->Enable(em.HasPresets(ID));
|
||||
|
||||
if (command.first == mCommand->GetValue())
|
||||
if (std::get<0>( command ) == mCommand->GetValue())
|
||||
return;
|
||||
|
||||
mCommand->SetValue(command.first);
|
||||
mInternalCommandName = command.second;
|
||||
mCommand->SetValue(std::get<0> (command));
|
||||
mInternalCommandName = std::get<1>( command );
|
||||
|
||||
wxString params = BatchCommands::GetCurrentParamsFor(command.second);
|
||||
wxString params = BatchCommands::GetCurrentParamsFor(mInternalCommandName);
|
||||
if (params.IsEmpty())
|
||||
{
|
||||
params = em.GetDefaultPreset(ID);
|
||||
}
|
||||
|
||||
// Cryptic command and category.
|
||||
// Later we can put help information there, perhaps.
|
||||
mDetails->SetValue( mInternalCommandName + "\r\n" + std::get<2>(command) );
|
||||
mParameters->SetValue(params);
|
||||
}
|
||||
|
||||
@ -215,7 +204,7 @@ void BatchCommandDialog::OnUsePreset(wxCommandEvent & WXUNUSED(event))
|
||||
void BatchCommandDialog::SetCommandAndParams(const wxString &Command, const wxString &Params)
|
||||
{
|
||||
auto item = make_iterator_range(mCommandNames).index_if(
|
||||
[&](const CommandName &name){ return Command == name.second; }
|
||||
[&](const CommandName &name){ return Command == std::get<1>( name); }
|
||||
);
|
||||
|
||||
mParameters->SetValue( Params );
|
||||
@ -224,7 +213,8 @@ void BatchCommandDialog::SetCommandAndParams(const wxString &Command, const wxSt
|
||||
if (item < 0)
|
||||
mCommand->SetValue( Command );
|
||||
else {
|
||||
mCommand->SetValue( mCommandNames[item].first );
|
||||
mCommand->SetValue( std::get<0>( mCommandNames[item]) );
|
||||
mDetails->SetValue( std::get<1>(mCommandNames[item]) + "\r\n" + std::get<2>(mCommandNames[item]) );
|
||||
mChoices->SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
|
||||
|
||||
EffectManager & em = EffectManager::Get();
|
||||
|
@ -12,6 +12,7 @@
|
||||
#ifndef __AUDACITY_BATCH_COMMAND_DIALOG__
|
||||
#define __AUDACITY_BATCH_COMMAND_DIALOG__
|
||||
|
||||
#include <tuple>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
@ -63,10 +64,11 @@ class BatchCommandDialog final : public wxDialogWrapper {
|
||||
wxListCtrl *mChoices;
|
||||
wxTextCtrl * mCommand;
|
||||
wxTextCtrl * mParameters;
|
||||
wxTextCtrl * mDetails;
|
||||
|
||||
wxString mInternalCommandName;
|
||||
|
||||
using CommandName = std::pair<wxString, wxString>;
|
||||
using CommandName = std::tuple<wxString, wxString,wxString>;
|
||||
using CommandNameVector = std::vector<CommandName>;
|
||||
CommandNameVector mCommandNames;
|
||||
|
||||
|
@ -73,6 +73,8 @@ static const std::pair<const wxChar*, const wxChar*> SpecialCommands[] = {
|
||||
/* i18n-hint: FLAC names an audio file format */
|
||||
{ XO("Export as FLAC"), wxT("ExportFLAC") },
|
||||
|
||||
// MP3 OGG and WAV already handled by menu items.
|
||||
#if 0
|
||||
/* i18n-hint: MP3 names an audio file format */
|
||||
{ XO("Export as MP3"), wxT("ExportMP3") },
|
||||
|
||||
@ -81,6 +83,7 @@ static const std::pair<const wxChar*, const wxChar*> SpecialCommands[] = {
|
||||
|
||||
/* i18n-hint: WAV names an audio file format */
|
||||
{ XO("Export as WAV"), wxT("ExportWAV") },
|
||||
#endif
|
||||
};
|
||||
// end CLEANSPEECH remnant
|
||||
|
||||
@ -258,11 +261,9 @@ auto BatchCommands::GetAllCommands() -> CommandNameVector
|
||||
|
||||
// CLEANSPEECH remnant
|
||||
for( const auto &command : SpecialCommands )
|
||||
commands.push_back( {
|
||||
//wxGetTranslation
|
||||
(command.first),
|
||||
command.second
|
||||
} );
|
||||
commands.push_back(
|
||||
CommandName( command.first, command.second, _("Special Command") )
|
||||
);
|
||||
|
||||
// end CLEANSPEECH remnant
|
||||
|
||||
@ -274,10 +275,14 @@ auto BatchCommands::GetAllCommands() -> CommandNameVector
|
||||
{
|
||||
auto command = em.GetCommandIdentifier(plug->GetID());
|
||||
if (!command.IsEmpty())
|
||||
commands.push_back( {
|
||||
plug->GetUntranslatedName(), // plug->GetTranslatedName(),
|
||||
command
|
||||
} );
|
||||
commands.push_back(
|
||||
CommandName(
|
||||
plug->GetUntranslatedName(), // plug->GetTranslatedName(),
|
||||
command,
|
||||
plug->GetPluginType() == PluginTypeEffect ?
|
||||
_("Effect") : _("Menu Command (With Parameters)")
|
||||
)
|
||||
);
|
||||
plug = pm.GetNextPlugin(PluginTypeEffect|PluginTypeAudacityCommand);
|
||||
}
|
||||
}
|
||||
@ -290,13 +295,26 @@ auto BatchCommands::GetAllCommands() -> CommandNameVector
|
||||
mManager->GetAllCommandLabels(mLabels, false);
|
||||
mManager->GetAllCommandNames(mNames, false);
|
||||
for(size_t i=0; i<mNames.GetCount(); i++) {
|
||||
if( !mLabels[i].Contains( "..." ) ){
|
||||
mLabels[i].Replace( "&", "" );
|
||||
wxString label = mLabels[i];
|
||||
if( !label.Contains( "..." ) ){
|
||||
label.Replace( "&", "" );
|
||||
wxString squashed = label;
|
||||
squashed.Replace( " ", "" );
|
||||
|
||||
// We'll disambiguate if the squashed name is short and shorter than the internal name.
|
||||
// Otherwise not.
|
||||
// This means we won't have repetitive items like "Cut (Cut)"
|
||||
// But we will show important disambiguation like "All (SelectAll)" and "By Date (SortByDate)"
|
||||
// Disambiguation is no longer essential as the details box will show it.
|
||||
if( squashed.Length() < wxMin( 18, mNames[i].Length()) )
|
||||
label = label + " (" + mNames[i] + ")";
|
||||
|
||||
commands.push_back(
|
||||
{
|
||||
mLabels[i] + " (" + mNames[i] + ")", // User readable name
|
||||
mNames[i] // Internal name.
|
||||
}
|
||||
CommandName(
|
||||
label, // User readable name
|
||||
mNames[i], // Internal name.
|
||||
_("Menu Command (No Parameters)")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -307,15 +325,22 @@ auto BatchCommands::GetAllCommands() -> CommandNameVector
|
||||
std::sort(
|
||||
commands.begin(), commands.end(),
|
||||
[](const CommandName &a, const CommandName &b)
|
||||
{ return a.first < b.first; }
|
||||
{ return std::get<0>(a) < std::get<0>(b); }
|
||||
);
|
||||
|
||||
|
||||
|
||||
return commands;
|
||||
// JKC: Gave up on trying to use std::unique on this.
|
||||
CommandNameVector uniqueCommands;
|
||||
unsigned size = commands.size();
|
||||
wxString oldName = "";
|
||||
for( unsigned i = 0; i < size; ++i )
|
||||
{
|
||||
if( std::get<0>( commands[i] ) != oldName )
|
||||
uniqueCommands.push_back( commands[i] );
|
||||
oldName = std::get<0>( commands[i] );
|
||||
}
|
||||
return uniqueCommands;
|
||||
}
|
||||
|
||||
|
||||
wxString BatchCommands::GetCurrentParamsFor(const wxString & command)
|
||||
{
|
||||
const PluginID & ID = EffectManager::Get().GetEffectByIdentifier(command);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#ifndef __AUDACITY_BATCH_COMMANDS_DIALOG__
|
||||
#define __AUDACITY_BATCH_COMMANDS_DIALOG__
|
||||
|
||||
#include <tuple>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
@ -43,7 +44,7 @@ class BatchCommands final {
|
||||
static wxArrayString GetNames();
|
||||
|
||||
// A pair of user-visible name, and internal string identifier
|
||||
using CommandName = std::pair<wxString, wxString>;
|
||||
using CommandName = std::tuple<wxString, wxString, wxString>;
|
||||
using CommandNameVector = std::vector<CommandName>;
|
||||
// Result is sorted by user-visible name
|
||||
static CommandNameVector GetAllCommands();
|
||||
|
@ -65,18 +65,19 @@ BEGIN_EVENT_TABLE(BatchProcessDialog, wxDialogWrapper)
|
||||
EVT_BUTTON(wxID_CANCEL, BatchProcessDialog::OnCancel)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
BatchProcessDialog::BatchProcessDialog(wxWindow * parent):
|
||||
BatchProcessDialog::BatchProcessDialog(wxWindow * parent, bool bInherited):
|
||||
wxDialogWrapper(parent, wxID_ANY, _("Apply Chain"),
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
//AudacityProject * p = GetActiveProject();
|
||||
|
||||
mAbort = false;
|
||||
if( bInherited )
|
||||
return;
|
||||
SetLabel(_("Apply Chain")); // Provide visual label
|
||||
SetName(_("Apply Chain")); // Provide audible label
|
||||
Populate();
|
||||
|
||||
mAbort = false;
|
||||
}
|
||||
|
||||
BatchProcessDialog::~BatchProcessDialog()
|
||||
@ -422,21 +423,25 @@ void BatchProcessDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
|
||||
#include "BatchCommandDialog.h"
|
||||
|
||||
enum {
|
||||
// ChainsListID 7005
|
||||
AddButtonID = 10000,
|
||||
RemoveButtonID,
|
||||
// CommandsListID, 7002
|
||||
ImportButtonID,
|
||||
ExportButtonID,
|
||||
DefaultsButtonID,
|
||||
InsertButtonID,
|
||||
EditButtonID,
|
||||
DeleteButtonID,
|
||||
UpButtonID,
|
||||
DownButtonID,
|
||||
RenameButtonID
|
||||
RenameButtonID,
|
||||
// ChainsListID 7005
|
||||
// CommandsListID, 7002
|
||||
// Re-Use IDs from BatchProcessDialog.
|
||||
ApplyToProjectButtonID = ApplyToProjectID,
|
||||
ApplyToFilesButtonID = ApplyToFilesID,
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(EditChainsDialog, wxDialogWrapper)
|
||||
BEGIN_EVENT_TABLE(EditChainsDialog, BatchProcessDialog)
|
||||
EVT_LIST_ITEM_SELECTED(ChainsListID, EditChainsDialog::OnChainSelected)
|
||||
EVT_LIST_ITEM_SELECTED(CommandsListID, EditChainsDialog::OnListSelected)
|
||||
EVT_LIST_BEGIN_LABEL_EDIT(ChainsListID, EditChainsDialog::OnChainsBeginEdit)
|
||||
@ -448,6 +453,7 @@ BEGIN_EVENT_TABLE(EditChainsDialog, wxDialogWrapper)
|
||||
|
||||
EVT_LIST_ITEM_ACTIVATED(CommandsListID, EditChainsDialog::OnCommandActivated)
|
||||
EVT_BUTTON(InsertButtonID, EditChainsDialog::OnInsert)
|
||||
EVT_BUTTON(EditButtonID, EditChainsDialog::OnEditCommandParams)
|
||||
EVT_BUTTON(DeleteButtonID, EditChainsDialog::OnDelete)
|
||||
EVT_BUTTON(UpButtonID, EditChainsDialog::OnUp)
|
||||
EVT_BUTTON(DownButtonID, EditChainsDialog::OnDown)
|
||||
@ -468,12 +474,14 @@ enum {
|
||||
|
||||
/// Constructor
|
||||
EditChainsDialog::EditChainsDialog(wxWindow * parent):
|
||||
wxDialogWrapper(parent, wxID_ANY, _("Edit Chains"),
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
BatchProcessDialog(parent, true)
|
||||
// , wxID_ANY, _("Edit Chains"),
|
||||
// wxDefaultPosition, wxDefaultSize,
|
||||
// wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
SetLabel(_("Edit Chains")); // Provide visual label
|
||||
SetName(_("Edit Chains")); // Provide audible label
|
||||
SetTitle(_("Edit Chains"));
|
||||
|
||||
mChanged = false;
|
||||
mSelectedCommand = 0;
|
||||
@ -571,11 +579,25 @@ void EditChainsDialog::PopulateOrExchange(ShuttleGui & S)
|
||||
|
||||
S.StartHorizontalLay(wxCENTER, false);
|
||||
{
|
||||
S.Id(InsertButtonID).AddButton(_("&Insert"), wxALIGN_LEFT);
|
||||
S.Id(DeleteButtonID).AddButton(_("De&lete"), wxALIGN_LEFT);
|
||||
S.Id(UpButtonID).AddButton(_("Move &Up"), wxALIGN_LEFT);
|
||||
S.Id(DownButtonID).AddButton(_("Move &Down"), wxALIGN_LEFT);
|
||||
mDefaults = S.Id(DefaultsButtonID).AddButton(_("De&faults"));
|
||||
S.AddPrompt( _("Command:") );
|
||||
S.StartHorizontalLay(wxCENTER, false);
|
||||
{
|
||||
S.Id(InsertButtonID).AddButton(_("&Insert"), wxALIGN_LEFT);
|
||||
S.Id(EditButtonID).AddButton(_("&Edit"), wxALIGN_LEFT);
|
||||
S.Id(DeleteButtonID).AddButton(_("De&lete"), wxALIGN_LEFT);
|
||||
S.Id(UpButtonID).AddButton(_("Move &Up"), wxALIGN_LEFT);
|
||||
S.Id(DownButtonID).AddButton(_("Move &Down"), wxALIGN_LEFT);
|
||||
mDefaults = S.Id(DefaultsButtonID).AddButton(_("De&faults"));
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
S.AddSpace( 40 );
|
||||
S.AddPrompt( _("Apply Chain to:") );
|
||||
S.StartHorizontalLay(wxCENTER, false);
|
||||
{
|
||||
S.Id(ApplyToProjectButtonID).AddButton(_("&Project"), wxALIGN_LEFT);
|
||||
S.Id(ApplyToFilesButtonID).AddButton(_("&Files"), wxALIGN_LEFT);
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
}
|
||||
S.EndHorizontalLay();
|
||||
}
|
||||
@ -633,11 +655,11 @@ void EditChainsDialog::AddItem(const wxString &Action, const wxString &Params)
|
||||
{
|
||||
// Translate internal command name to a friendly form
|
||||
auto item = make_iterator_range(mCommandNames).index_if(
|
||||
[&](const CommandName &name){ return Action == name.second; }
|
||||
[&](const CommandName &name){ return Action == std::get<1>(name); }
|
||||
);
|
||||
auto friendlyName = item >= 0
|
||||
? // wxGetTranslation
|
||||
( mCommandNames[item].first )
|
||||
std::get<0>( mCommandNames[item] )
|
||||
: Action;
|
||||
|
||||
int i = mList->GetItemCount();
|
||||
@ -881,6 +903,10 @@ void EditChainsDialog::OnRename(wxCommandEvent & WXUNUSED(event))
|
||||
/// Bring up a dialog to allow its parameters to be edited.
|
||||
void EditChainsDialog::OnCommandActivated(wxListEvent &event)
|
||||
{
|
||||
wxCommandEvent dummy;
|
||||
OnEditCommandParams( dummy );
|
||||
|
||||
#if 0
|
||||
int item = event.GetIndex();
|
||||
|
||||
BatchCommandDialog d(this, wxID_ANY);
|
||||
@ -901,6 +927,7 @@ void EditChainsDialog::OnCommandActivated(wxListEvent &event)
|
||||
mSelectedCommand = item;
|
||||
|
||||
PopulateList();
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
@ -909,6 +936,14 @@ void EditChainsDialog::OnInsert(wxCommandEvent & WXUNUSED(event))
|
||||
long item = mList->GetNextItem(-1,
|
||||
wxLIST_NEXT_ALL,
|
||||
wxLIST_STATE_SELECTED);
|
||||
if (item == -1) {
|
||||
item = mList->GetItemCount()-1;
|
||||
}
|
||||
InsertCommandAt( item );
|
||||
}
|
||||
|
||||
void EditChainsDialog::InsertCommandAt(int item)
|
||||
{
|
||||
if (item == -1) {
|
||||
return;
|
||||
}
|
||||
@ -925,13 +960,42 @@ void EditChainsDialog::OnInsert(wxCommandEvent & WXUNUSED(event))
|
||||
d.mSelectedParameters,
|
||||
item);
|
||||
mChanged = true;
|
||||
|
||||
mSelectedCommand = item + 1;
|
||||
|
||||
PopulateList();
|
||||
}
|
||||
}
|
||||
|
||||
void EditChainsDialog::OnEditCommandParams(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
int item = mList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
|
||||
|
||||
// LAST command in list is END.
|
||||
// If nothing selected, add at END.
|
||||
// If END selected, add at END.
|
||||
// When adding at end we use InsertCommandAt, so that a new command
|
||||
// can be chosen.
|
||||
int lastItem = mList->GetItemCount()-1;
|
||||
if( (item<0) || (item+1) == mList->GetItemCount() )
|
||||
{
|
||||
InsertCommandAt( lastItem );
|
||||
return;
|
||||
}
|
||||
|
||||
// Just edit the parameters, and not the command.
|
||||
wxString command = mBatchCommands.GetCommand(item);
|
||||
wxString params = mBatchCommands.GetParams(item);
|
||||
|
||||
params = BatchCommands::PromptForParamsFor(command, params, this).Trim();
|
||||
|
||||
mBatchCommands.DeleteFromChain(item);
|
||||
mBatchCommands.AddToChain(command,
|
||||
params,
|
||||
item);
|
||||
mChanged = true;
|
||||
mSelectedCommand = item;
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
///
|
||||
void EditChainsDialog::OnDelete(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
@ -943,15 +1007,12 @@ void EditChainsDialog::OnDelete(wxCommandEvent & WXUNUSED(event))
|
||||
}
|
||||
|
||||
mBatchCommands.DeleteFromChain(item);
|
||||
|
||||
mChanged = true;
|
||||
|
||||
if (item >= (mList->GetItemCount() - 2) && item >= 0) {
|
||||
item--;
|
||||
}
|
||||
|
||||
mSelectedCommand = item;
|
||||
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
@ -969,11 +1030,8 @@ void EditChainsDialog::OnUp(wxCommandEvent & WXUNUSED(event))
|
||||
mBatchCommands.GetParams(item),
|
||||
item - 1);
|
||||
mBatchCommands.DeleteFromChain(item + 1);
|
||||
|
||||
mChanged = true;
|
||||
|
||||
mSelectedCommand = item - 1;
|
||||
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
@ -991,14 +1049,25 @@ void EditChainsDialog::OnDown(wxCommandEvent & WXUNUSED(event))
|
||||
mBatchCommands.GetParams(item),
|
||||
item + 2);
|
||||
mBatchCommands.DeleteFromChain(item);
|
||||
|
||||
mChanged = true;
|
||||
|
||||
mSelectedCommand = item + 1;
|
||||
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
void EditChainsDialog::OnApplyToProject(wxCommandEvent & event)
|
||||
{
|
||||
if( !SaveChanges() )
|
||||
return;
|
||||
BatchProcessDialog::OnApplyToProject( event );
|
||||
}
|
||||
|
||||
void EditChainsDialog::OnApplyToFiles(wxCommandEvent & event)
|
||||
{
|
||||
if( !SaveChanges() )
|
||||
return;
|
||||
BatchProcessDialog::OnApplyToFiles( event );
|
||||
}
|
||||
|
||||
/// Select the empty Command chain.
|
||||
void EditChainsDialog::OnDefaults(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
@ -1009,29 +1078,35 @@ void EditChainsDialog::OnDefaults(wxCommandEvent & WXUNUSED(event))
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
/// Send changed values back to Prefs, and update Audacity.
|
||||
void EditChainsDialog::OnOK(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
bool EditChainsDialog::SaveChanges(){
|
||||
gPrefs->Write(wxT("/Batch/ActiveChain"), mActiveChain);
|
||||
gPrefs->Flush();
|
||||
|
||||
if (mChanged) {
|
||||
if (!mBatchCommands.WriteChain(mActiveChain)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mChanged = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Send changed values back to Prefs, and update Audacity.
|
||||
void EditChainsDialog::OnOK(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
if( !SaveChanges() )
|
||||
return;
|
||||
EndModal(true);
|
||||
}
|
||||
|
||||
///
|
||||
void EditChainsDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
|
||||
void EditChainsDialog::OnCancel(wxCommandEvent & event)
|
||||
{
|
||||
if (!ChangeOK()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EndModal(false);
|
||||
BatchProcessDialog::OnCancel( event );
|
||||
//EndModal(false);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -39,40 +39,45 @@ class wxButton;
|
||||
class wxTextCtrl;
|
||||
class ShuttleGui;
|
||||
|
||||
class BatchProcessDialog final : public wxDialogWrapper {
|
||||
class BatchProcessDialog : public wxDialogWrapper {
|
||||
public:
|
||||
// constructors and destructors
|
||||
BatchProcessDialog(wxWindow * parent);
|
||||
BatchProcessDialog(wxWindow * parent, bool bInherited=false);
|
||||
virtual ~BatchProcessDialog();
|
||||
public:
|
||||
void Populate();
|
||||
void PopulateOrExchange( ShuttleGui & S );
|
||||
virtual void Populate();
|
||||
virtual void PopulateOrExchange( ShuttleGui & S );
|
||||
virtual void OnApplyToProject(wxCommandEvent & event);
|
||||
virtual void OnApplyToFiles(wxCommandEvent & event);
|
||||
virtual void OnCancel(wxCommandEvent & event);
|
||||
|
||||
void OnApplyToProject(wxCommandEvent & event);
|
||||
void OnApplyToFiles(wxCommandEvent & event);
|
||||
void OnCancel(wxCommandEvent & event);
|
||||
// These will be reused in the derived class...
|
||||
wxListCtrl *mList;
|
||||
wxListCtrl *mChains;
|
||||
BatchCommands mBatchCommands; /// Provides list of available commands.
|
||||
|
||||
wxButton *mOK;
|
||||
wxButton *mCancel;
|
||||
wxListCtrl *mChains;
|
||||
wxListCtrl *mList;
|
||||
BatchCommands mBatchCommands;
|
||||
wxTextCtrl *mResults;
|
||||
|
||||
bool mAbort;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
class EditChainsDialog final : public wxDialogWrapper
|
||||
class EditChainsDialog final : public BatchProcessDialog
|
||||
{
|
||||
public:
|
||||
EditChainsDialog(wxWindow * parent);
|
||||
~EditChainsDialog();
|
||||
|
||||
private:
|
||||
void Populate();
|
||||
void PopulateOrExchange(ShuttleGui &S);
|
||||
void Populate() override;
|
||||
void PopulateOrExchange(ShuttleGui &S) override;
|
||||
void OnApplyToProject(wxCommandEvent & event) override;
|
||||
void OnApplyToFiles(wxCommandEvent & event) override;
|
||||
void OnCancel(wxCommandEvent &event) override;
|
||||
|
||||
|
||||
void PopulateChains();
|
||||
void PopulateList();
|
||||
void AddItem(const wxString &command, wxString const ¶ms);
|
||||
@ -89,31 +94,39 @@ private:
|
||||
|
||||
void OnCommandActivated(wxListEvent &event);
|
||||
void OnInsert(wxCommandEvent &event);
|
||||
void OnEditCommandParams(wxCommandEvent &event);
|
||||
|
||||
void OnDelete(wxCommandEvent &event);
|
||||
void OnUp(wxCommandEvent &event);
|
||||
void OnDown(wxCommandEvent &event);
|
||||
void OnDefaults(wxCommandEvent &event);
|
||||
|
||||
//void OnApplyToProject(wxCommandEvent &event);
|
||||
//void OnApplyToFiles(wxCommandEvent &event);
|
||||
|
||||
void OnOK(wxCommandEvent &event);
|
||||
void OnCancel(wxCommandEvent &event);
|
||||
|
||||
void OnKeyDown(wxKeyEvent &event);
|
||||
void FitColumns();
|
||||
void InsertCommandAt(int item);
|
||||
bool SaveChanges();
|
||||
|
||||
// These are already provided by BatchProcessDialog
|
||||
//wxListCtrl *mList; /// List of commands in current command chain.
|
||||
//BatchCommands mBatchCommands; /// Provides list of available commands.
|
||||
//wxListCtrl *mChains; /// List of chains.
|
||||
|
||||
wxListCtrl *mChains; /// List of chains.
|
||||
wxListCtrl *mList; /// List of commands in current command chain.
|
||||
wxButton *mRemove;
|
||||
wxButton *mRename;
|
||||
wxButton *mDefaults;
|
||||
|
||||
|
||||
BatchCommands mBatchCommands; /// Provides list of available commands.
|
||||
wxString mActiveChain;
|
||||
|
||||
int mSelectedCommand;
|
||||
bool mChanged;
|
||||
|
||||
using CommandName = std::pair<wxString, wxString>;
|
||||
using CommandName = std::tuple<wxString, wxString,wxString>;
|
||||
using CommandNameVector = std::vector<CommandName>;
|
||||
CommandNameVector mCommandNames;
|
||||
|
||||
|
@ -1230,8 +1230,8 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddItem(wxT("QuickHelp"), _("&Getting Started"), FN(OnQuickHelp));
|
||||
c->AddItem(wxT("Manual"), wxT("Audacity &Manual"), FN(OnManual));
|
||||
#else
|
||||
c->AddItem(wxT("QuickHelp"), _("&Quick Help"), FN(OnQuickHelp));
|
||||
c->AddItem(wxT("Manual"), _("&Manual"), FN(OnManual));
|
||||
c->AddItem(wxT("QuickHelp"), _("&Quick Help..."), FN(OnQuickHelp));
|
||||
c->AddItem(wxT("Manual"), _("&Manual..."), FN(OnManual));
|
||||
#endif
|
||||
|
||||
|
||||
@ -1371,10 +1371,10 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->SetDefaultFlags(AlwaysEnabledFlag, AlwaysEnabledFlag);
|
||||
c->BeginSubMenu(_("Mi&xer"));
|
||||
|
||||
c->AddItem(wxT("OutputGain"), _("Ad&just Playback Volume"), FN(OnOutputGain));
|
||||
c->AddItem(wxT("OutputGain"), _("Ad&just Playback Volume..."), FN(OnOutputGain));
|
||||
c->AddItem(wxT("OutputGainInc"), _("&Increase Playback Volume"), FN(OnOutputGainInc));
|
||||
c->AddItem(wxT("OutputGainDec"), _("&Decrease Playback Volume"), FN(OnOutputGainDec));
|
||||
c->AddItem(wxT("InputGain"), _("Adj&ust Recording Volume"), FN(OnInputGain));
|
||||
c->AddItem(wxT("InputGain"), _("Adj&ust Recording Volume..."), FN(OnInputGain));
|
||||
c->AddItem(wxT("InputGainInc"), _("I&ncrease Recording Volume"), FN(OnInputGainInc));
|
||||
c->AddItem(wxT("InputGainDec"), _("D&ecrease Recording Volume"), FN(OnInputGainDec));
|
||||
c->EndSubMenu();
|
||||
@ -1401,7 +1401,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddItem(wxT("PlayAtSpeed"), _("Pl&ay-at-Speed"), FN(OnPlayAtSpeed));
|
||||
c->AddItem(wxT("PlayAtSpeedLooped"), _("&Loop Play-at-Speed"), FN(OnPlayAtSpeedLooped));
|
||||
c->AddItem(wxT("PlayAtSpeedCutPreview"), _("Play C&ut Preview-at-Speed"), FN(OnPlayAtSpeedCutPreview));
|
||||
c->AddItem(wxT("SetPlaySpeed"), _("Ad&just Playback Speed"), FN(OnSetPlaySpeed));
|
||||
c->AddItem(wxT("SetPlaySpeed"), _("Ad&just Playback Speed..."), FN(OnSetPlaySpeed));
|
||||
c->AddItem(wxT("PlaySpeedInc"), _("&Increase Playback Speed"), FN(OnPlaySpeedInc));
|
||||
c->AddItem(wxT("PlaySpeedDec"), _("&Decrease Playback Speed"), FN(OnPlaySpeedDec));
|
||||
|
||||
@ -1429,16 +1429,16 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->SetDefaultFlags(AlwaysEnabledFlag, AlwaysEnabledFlag);
|
||||
c->BeginSubMenu(_("De&vice"));
|
||||
|
||||
c->AddItem(wxT("InputDevice"), _("Change &Recording Device"), FN(OnInputDevice), wxT("Shift+I"),
|
||||
c->AddItem(wxT("InputDevice"), _("Change &Recording Device..."), FN(OnInputDevice), wxT("Shift+I"),
|
||||
AudioIONotBusyFlag,
|
||||
AudioIONotBusyFlag);
|
||||
c->AddItem(wxT("OutputDevice"), _("Change &Playback Device"), FN(OnOutputDevice), wxT("Shift+O"),
|
||||
c->AddItem(wxT("OutputDevice"), _("Change &Playback Device..."), FN(OnOutputDevice), wxT("Shift+O"),
|
||||
AudioIONotBusyFlag,
|
||||
AudioIONotBusyFlag);
|
||||
c->AddItem(wxT("AudioHost"), _("Change Audio &Host"), FN(OnAudioHost), wxT("Shift+H"),
|
||||
c->AddItem(wxT("AudioHost"), _("Change Audio &Host..."), FN(OnAudioHost), wxT("Shift+H"),
|
||||
AudioIONotBusyFlag,
|
||||
AudioIONotBusyFlag);
|
||||
c->AddItem(wxT("InputChannels"), _("Change Recording Cha&nnels"), FN(OnInputChannels), wxT("Shift+N"),
|
||||
c->AddItem(wxT("InputChannels"), _("Change Recording Cha&nnels..."), FN(OnInputChannels), wxT("Shift+N"),
|
||||
AudioIONotBusyFlag,
|
||||
AudioIONotBusyFlag);
|
||||
c->EndSubMenu();
|
||||
@ -1543,7 +1543,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->SetDefaultFlags(AlwaysEnabledFlag, AlwaysEnabledFlag);
|
||||
c->BeginSubMenu(_("&Track"));
|
||||
|
||||
c->AddItem(wxT("TrackPan"), _("Change P&an on Focused Track"), FN(OnTrackPan), wxT("Shift+P"),
|
||||
c->AddItem(wxT("TrackPan"), _("Change P&an on Focused Track..."), FN(OnTrackPan), wxT("Shift+P"),
|
||||
TrackPanelHasFocus | TracksExistFlag,
|
||||
TrackPanelHasFocus | TracksExistFlag);
|
||||
c->AddItem(wxT("TrackPanLeft"), _("Pan &Left on Focused Track"), FN(OnTrackPanLeft), wxT("Alt+Shift+Left"),
|
||||
@ -1552,7 +1552,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddItem(wxT("TrackPanRight"), _("Pan &Right on Focused Track"), FN(OnTrackPanRight), wxT("Alt+Shift+Right"),
|
||||
TrackPanelHasFocus | TracksExistFlag,
|
||||
TrackPanelHasFocus | TracksExistFlag);
|
||||
c->AddItem(wxT("TrackGain"), _("Change Gai&n on Focused Track"), FN(OnTrackGain), wxT("Shift+G"),
|
||||
c->AddItem(wxT("TrackGain"), _("Change Gai&n on Focused Track..."), FN(OnTrackGain), wxT("Shift+G"),
|
||||
TrackPanelHasFocus | TracksExistFlag,
|
||||
TrackPanelHasFocus | TracksExistFlag);
|
||||
c->AddItem(wxT("TrackGainInc"), _("&Increase Gain on Focused Track"), FN(OnTrackGainInc), wxT("Alt+Shift+Up"),
|
||||
@ -1561,7 +1561,7 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddItem(wxT("TrackGainDec"), _("&Decrease Gain on Focused Track"), FN(OnTrackGainDec), wxT("Alt+Shift+Down"),
|
||||
TrackPanelHasFocus | TracksExistFlag,
|
||||
TrackPanelHasFocus | TracksExistFlag);
|
||||
c->AddItem(wxT("TrackMenu"), _("Op&en Menu on Focused Track"), FN(OnTrackMenu), wxT("Shift+M\tskipKeydown"),
|
||||
c->AddItem(wxT("TrackMenu"), _("Op&en Menu on Focused Track..."), FN(OnTrackMenu), wxT("Shift+M\tskipKeydown"),
|
||||
TracksExistFlag | TrackPanelHasFocus,
|
||||
TracksExistFlag | TrackPanelHasFocus);
|
||||
c->AddItem(wxT("TrackMute"), _("M&ute/Unmute Focused Track"), FN(OnTrackMute), wxT("Shift+U"),
|
||||
@ -1945,7 +1945,7 @@ void AudacityProject::AddEffectMenuItemGroup(CommandManager *c,
|
||||
item,
|
||||
FN(OnEffect),
|
||||
flags[i],
|
||||
flags[i], plugs[i]);
|
||||
flags[i], true, plugs[i]);
|
||||
|
||||
i++;
|
||||
}
|
||||
@ -1960,7 +1960,7 @@ void AudacityProject::AddEffectMenuItemGroup(CommandManager *c,
|
||||
names[i],
|
||||
FN(OnEffect),
|
||||
flags[i],
|
||||
flags[i], plugs[i]);
|
||||
flags[i], true, plugs[i]);
|
||||
}
|
||||
|
||||
if (max > 0)
|
||||
|
@ -760,7 +760,7 @@ void CommandManager::InsertItem(const wxString & name,
|
||||
}
|
||||
}
|
||||
|
||||
CommandListEntry *entry = NewIdentifier(name, label_in, menu, finder, callback, false, 0, 0);
|
||||
CommandListEntry *entry = NewIdentifier(name, label_in, menu, finder, callback, false, 0, 0, false);
|
||||
int ID = entry->id;
|
||||
wxString label = GetLabel(entry);
|
||||
|
||||
@ -804,9 +804,10 @@ void CommandManager::AddItem(const wxChar *name,
|
||||
CommandFunctorPointer callback,
|
||||
CommandFlag flags,
|
||||
CommandMask mask,
|
||||
bool bIsEffect,
|
||||
const CommandParameter ¶meter)
|
||||
{
|
||||
AddItem(name, label, finder, callback, wxT(""), flags, mask, -1, parameter);
|
||||
AddItem(name, label, finder, callback, wxT(""), flags, mask, -1, bIsEffect, parameter);
|
||||
}
|
||||
|
||||
void CommandManager::AddItem(const wxChar *name,
|
||||
@ -817,6 +818,7 @@ void CommandManager::AddItem(const wxChar *name,
|
||||
CommandFlag flags,
|
||||
CommandMask mask,
|
||||
int checkmark,
|
||||
bool bIsEffect,
|
||||
const CommandParameter ¶meter)
|
||||
{
|
||||
wxString cookedParameter;
|
||||
@ -826,7 +828,7 @@ void CommandManager::AddItem(const wxChar *name,
|
||||
cookedParameter = parameter;
|
||||
CommandListEntry *entry =
|
||||
NewIdentifier(name, label_in, accel, CurrentMenu(), finder, callback,
|
||||
false, 0, 0, cookedParameter);
|
||||
false, 0, 0, bIsEffect, cookedParameter);
|
||||
int ID = entry->id;
|
||||
wxString label = GetLabelWithDisabledAccel(entry);
|
||||
|
||||
@ -855,7 +857,8 @@ void CommandManager::AddItem(const wxChar *name,
|
||||
void CommandManager::AddItemList(const wxString & name,
|
||||
const wxArrayString & labels,
|
||||
CommandHandlerFinder finder,
|
||||
CommandFunctorPointer callback)
|
||||
CommandFunctorPointer callback,
|
||||
bool bIsEffect)
|
||||
{
|
||||
for (size_t i = 0, cnt = labels.GetCount(); i < cnt; i++) {
|
||||
CommandListEntry *entry = NewIdentifier(name,
|
||||
@ -865,7 +868,8 @@ void CommandManager::AddItemList(const wxString & name,
|
||||
callback,
|
||||
true,
|
||||
i,
|
||||
cnt);
|
||||
cnt,
|
||||
bIsEffect);
|
||||
CurrentMenu()->Append(entry->id, GetLabel(entry));
|
||||
mbSeparatorAllowed = true;
|
||||
}
|
||||
@ -892,7 +896,7 @@ void CommandManager::AddCommand(const wxChar *name,
|
||||
CommandFlag flags,
|
||||
CommandMask mask)
|
||||
{
|
||||
NewIdentifier(name, label_in, accel, NULL, finder, callback, false, 0, 0, {});
|
||||
NewIdentifier(name, label_in, accel, NULL, finder, callback, false, 0, 0, false, {});
|
||||
|
||||
if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
|
||||
SetCommandFlags(name, flags, mask);
|
||||
@ -907,7 +911,7 @@ void CommandManager::AddGlobalCommand(const wxChar *name,
|
||||
{
|
||||
CommandListEntry *entry =
|
||||
NewIdentifier(name, label_in, accel, NULL, finder, callback,
|
||||
false, 0, 0, {});
|
||||
false, 0, 0, false, {});
|
||||
|
||||
entry->enabled = false;
|
||||
entry->isGlobal = true;
|
||||
@ -945,7 +949,8 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & name,
|
||||
CommandFunctorPointer callback,
|
||||
bool multi,
|
||||
int index,
|
||||
int count)
|
||||
int count,
|
||||
bool bIsEffect)
|
||||
{
|
||||
return NewIdentifier(name,
|
||||
label.BeforeFirst(wxT('\t')),
|
||||
@ -955,7 +960,9 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & name,
|
||||
callback,
|
||||
multi,
|
||||
index,
|
||||
count, {});
|
||||
count,
|
||||
bIsEffect,
|
||||
{});
|
||||
}
|
||||
|
||||
CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn,
|
||||
@ -967,6 +974,7 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn,
|
||||
bool multi,
|
||||
int index,
|
||||
int count,
|
||||
bool bIsEffect,
|
||||
const CommandParameter ¶meter)
|
||||
{
|
||||
wxString name = nameIn;
|
||||
@ -1031,6 +1039,7 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn,
|
||||
entry->menu = menu;
|
||||
entry->finder = finder;
|
||||
entry->callback = callback;
|
||||
entry->isEffect = bIsEffect;
|
||||
entry->multi = multi;
|
||||
entry->index = index;
|
||||
entry->count = count;
|
||||
@ -1644,6 +1653,8 @@ void CommandManager::GetAllCommandNames(wxArrayString &names,
|
||||
bool includeMultis)
|
||||
{
|
||||
for(const auto &entry : mCommandList) {
|
||||
if ( entry->isEffect )
|
||||
continue;
|
||||
if (!entry->multi)
|
||||
names.Add(entry->name);
|
||||
else if( includeMultis )
|
||||
@ -1655,6 +1666,12 @@ void CommandManager::GetAllCommandLabels(wxArrayString &names,
|
||||
bool includeMultis)
|
||||
{
|
||||
for(const auto &entry : mCommandList) {
|
||||
// This is fetching commands from the menus, for use as batch commands.
|
||||
// Until we have properly merged EffectManager and CommandManager
|
||||
// we explicitly exclude effects, as they are already handled by the
|
||||
// effects Manager.
|
||||
if ( entry->isEffect )
|
||||
continue;
|
||||
if (!entry->multi)
|
||||
names.Add(entry->label);
|
||||
else if( includeMultis )
|
||||
@ -1674,6 +1691,8 @@ void CommandManager::GetAllCommandData(
|
||||
bool includeMultis)
|
||||
{
|
||||
for(const auto &entry : mCommandList) {
|
||||
if ( entry->isEffect )
|
||||
continue;
|
||||
if (!entry->multi)
|
||||
{
|
||||
names.Add(entry->name);
|
||||
|
@ -81,6 +81,7 @@ struct CommandListEntry
|
||||
bool wantKeyup;
|
||||
bool isGlobal;
|
||||
bool isOccult;
|
||||
bool isEffect;
|
||||
CommandFlag flags;
|
||||
CommandMask mask;
|
||||
};
|
||||
@ -162,7 +163,8 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler
|
||||
void AddItemList(const wxString & name,
|
||||
const wxArrayString & labels,
|
||||
CommandHandlerFinder finder,
|
||||
CommandFunctorPointer callback);
|
||||
CommandFunctorPointer callback,
|
||||
bool bIsEffect = false);
|
||||
|
||||
void AddCheck(const wxChar *name,
|
||||
const wxChar *label,
|
||||
@ -184,6 +186,7 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler
|
||||
CommandFunctorPointer callback,
|
||||
CommandFlag flags = NoFlagsSpecifed,
|
||||
CommandMask mask = NoFlagsSpecifed,
|
||||
bool bIsEffect = false,
|
||||
const CommandParameter ¶meter = CommandParameter{});
|
||||
|
||||
void AddItem(const wxChar *name,
|
||||
@ -194,6 +197,7 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler
|
||||
CommandFlag flags = NoFlagsSpecifed,
|
||||
CommandMask mask = NoFlagsSpecifed,
|
||||
int checkmark = -1,
|
||||
bool bIsEffect = false,
|
||||
const CommandParameter ¶meter = CommandParameter{});
|
||||
|
||||
void AddSeparator();
|
||||
@ -335,7 +339,8 @@ protected:
|
||||
CommandFunctorPointer callback,
|
||||
bool multi,
|
||||
int index,
|
||||
int count);
|
||||
int count,
|
||||
bool bIsEffect);
|
||||
CommandListEntry *NewIdentifier(const wxString & name,
|
||||
const wxString & label,
|
||||
const wxString & accel,
|
||||
@ -345,6 +350,7 @@ protected:
|
||||
bool multi,
|
||||
int index,
|
||||
int count,
|
||||
bool bIsEffect,
|
||||
const CommandParameter ¶meter);
|
||||
|
||||
//
|
||||
|
Loading…
x
Reference in New Issue
Block a user