mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-01 08:29:27 +02:00
Register preference pages, importers, exporters without sequence nos.
This commit is contained in:
commit
c96fd0d2be
@ -282,6 +282,24 @@ BEGIN_EVENT_TABLE(Exporter, wxEvtHandler)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
namespace {
|
||||
const auto PathStart = wxT("Exporters");
|
||||
|
||||
static Registry::GroupItem &sRegistry()
|
||||
{
|
||||
static Registry::TransparentGroupItem<> registry{ PathStart };
|
||||
return registry;
|
||||
}
|
||||
|
||||
struct ExporterItem final : Registry::SingleItem {
|
||||
ExporterItem(
|
||||
const Identifier &id, const Exporter::ExportPluginFactory &factory )
|
||||
: SingleItem{ id }
|
||||
, mFactory{ factory }
|
||||
{}
|
||||
|
||||
Exporter::ExportPluginFactory mFactory;
|
||||
};
|
||||
|
||||
using ExportPluginFactories = std::vector< Exporter::ExportPluginFactory >;
|
||||
ExportPluginFactories &sFactories()
|
||||
{
|
||||
@ -291,15 +309,24 @@ namespace {
|
||||
}
|
||||
|
||||
Exporter::RegisteredExportPlugin::RegisteredExportPlugin(
|
||||
const ExportPluginFactory &factory )
|
||||
const Identifier &id,
|
||||
const ExportPluginFactory &factory,
|
||||
const Registry::Placement &placement )
|
||||
{
|
||||
if ( factory )
|
||||
sFactories().emplace_back( factory );
|
||||
Registry::RegisterItem( sRegistry(), placement,
|
||||
std::make_unique< ExporterItem >( id, factory ) );
|
||||
}
|
||||
|
||||
Exporter::Exporter( AudacityProject &project )
|
||||
: mProject{ &project }
|
||||
{
|
||||
using namespace Registry;
|
||||
static OrderingPreferenceInitializer init{
|
||||
PathStart,
|
||||
{ {wxT(""), wxT("PCM,MP3,OGG,FLAC,MP2,CommandLine,FFmpeg") } },
|
||||
};
|
||||
|
||||
mMixerSpec = NULL;
|
||||
mBook = NULL;
|
||||
|
||||
@ -307,15 +334,25 @@ Exporter::Exporter( AudacityProject &project )
|
||||
for ( const auto &factory : sFactories() )
|
||||
mPlugins.emplace_back( factory() );
|
||||
|
||||
// The factories were pushed on the array at static initialization time in an
|
||||
// unspecified sequence. Sort according to the sequence numbers the plugins
|
||||
// report to make the order determinate.
|
||||
std::sort( mPlugins.begin(), mPlugins.end(),
|
||||
[]( const ExportPluginArray::value_type &a,
|
||||
const ExportPluginArray::value_type &b ){
|
||||
return a->SequenceNumber() < b->SequenceNumber();
|
||||
struct MyVisitor final : Visitor {
|
||||
MyVisitor()
|
||||
{
|
||||
// visit the registry to collect the plug-ins properly
|
||||
// sorted
|
||||
TransparentGroupItem<> top{ PathStart };
|
||||
Registry::Visit( *this, &top, &sRegistry() );
|
||||
}
|
||||
);
|
||||
|
||||
void Visit( SingleItem &item, const Path &path ) override
|
||||
{
|
||||
mPlugins.emplace_back(
|
||||
static_cast<ExporterItem&>( item ).mFactory() );
|
||||
}
|
||||
|
||||
ExportPluginArray mPlugins;
|
||||
} visitor;
|
||||
|
||||
mPlugins.swap( visitor.mPlugins );
|
||||
|
||||
SetFileDialogTitle( XO("Export Audio") );
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "../widgets/wxPanelWrapper.h" // to inherit
|
||||
#include "../FileNames.h" // for FileTypes
|
||||
|
||||
#include "../commands/CommandManager.h" // for Registry::Placement
|
||||
|
||||
class wxArrayString;
|
||||
class FileDialogWrapper;
|
||||
class wxFileCtrlEvent;
|
||||
@ -132,8 +134,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) = 0;
|
||||
|
||||
virtual unsigned SequenceNumber() const = 0;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Mixer> CreateMixer(const TrackList &tracks,
|
||||
bool selectionOnly,
|
||||
@ -174,7 +174,10 @@ public:
|
||||
// to have some fresh state variables each time export begins again
|
||||
// and to compute translated strings for the current locale
|
||||
struct RegisteredExportPlugin{
|
||||
RegisteredExportPlugin( const ExportPluginFactory& );
|
||||
RegisteredExportPlugin(
|
||||
const Identifier &id, // an internal string naming the plug-in
|
||||
const ExportPluginFactory&,
|
||||
const Registry::Placement &placement = { wxEmptyString, {} } );
|
||||
};
|
||||
|
||||
static bool DoEditMetadata(AudacityProject &project,
|
||||
|
@ -310,8 +310,6 @@ public:
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 60; }
|
||||
};
|
||||
|
||||
ExportCL::ExportCL()
|
||||
@ -567,5 +565,6 @@ void ExportCL::OptionsCreate(ShuttleGui &S, int format)
|
||||
S.AddWindow( safenew ExportCLOptions{ S.GetParent(), format } );
|
||||
}
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportCL >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "CommandLine",
|
||||
[]{ return std::make_unique< ExportCL >(); }
|
||||
};
|
||||
|
@ -152,8 +152,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 70; }
|
||||
|
||||
private:
|
||||
|
||||
AVOutputFormat * mEncFormatDesc{}; // describes our output file to libavformat
|
||||
@ -1141,8 +1139,9 @@ void ExportFFmpeg::OptionsCreate(ShuttleGui &S, int format)
|
||||
ExportPlugin::OptionsCreate(S, format);
|
||||
}
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportFFmpeg >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "FFmpeg",
|
||||
[]{ return std::make_unique< ExportFFmpeg >(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -224,8 +224,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 40; }
|
||||
|
||||
private:
|
||||
|
||||
bool GetMetadata(AudacityProject *project, const Tags *tags);
|
||||
@ -474,8 +472,9 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
|
||||
return true;
|
||||
}
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportFLAC >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "FLAC",
|
||||
[]{ return std::make_unique< ExportFLAC >(); }
|
||||
};
|
||||
|
||||
#endif // USE_LIBFLAC
|
||||
|
||||
|
@ -217,8 +217,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 50; }
|
||||
|
||||
private:
|
||||
|
||||
int AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
|
||||
@ -498,8 +496,9 @@ void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
||||
}
|
||||
#endif
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportMP2 >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "MP2",
|
||||
[]{ return std::make_unique< ExportMP2 >(); }
|
||||
};
|
||||
|
||||
#endif // #ifdef USE_LIBTWOLAME
|
||||
|
||||
|
@ -1687,8 +1687,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 20; }
|
||||
|
||||
private:
|
||||
|
||||
int AskResample(int bitrate, int rate, int lowrate, int highrate);
|
||||
@ -2199,8 +2197,9 @@ void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
|
||||
}
|
||||
#endif
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportMP3 >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "MP3",
|
||||
[]{ return std::make_unique< ExportMP3 >(); }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Return library version
|
||||
|
@ -143,8 +143,6 @@ public:
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 30; }
|
||||
|
||||
private:
|
||||
|
||||
bool FillComment(AudacityProject *project, vorbis_comment *comment, const Tags *metadata);
|
||||
@ -398,8 +396,9 @@ bool ExportOGG::FillComment(AudacityProject *project, vorbis_comment *comment, c
|
||||
return true;
|
||||
}
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportOGG >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "OGG",
|
||||
[]{ return std::make_unique< ExportOGG >(); }
|
||||
};
|
||||
|
||||
#endif // USE_LIBVORBIS
|
||||
|
||||
|
@ -342,8 +342,6 @@ public:
|
||||
FileExtension GetExtension(int index) override;
|
||||
bool CheckFileName(wxFileName &filename, int format) override;
|
||||
|
||||
virtual unsigned SequenceNumber() const override { return 10; }
|
||||
|
||||
private:
|
||||
void ReportTooBigError(wxWindow * pParent);
|
||||
ArrayOf<char> AdjustString(const wxString & wxStr, int sf_format);
|
||||
@ -971,5 +969,6 @@ bool ExportPCM::CheckFileName(wxFileName &filename, int format)
|
||||
return ExportPlugin::CheckFileName(filename, format);
|
||||
}
|
||||
|
||||
static Exporter::RegisteredExportPlugin
|
||||
sRegisteredPlugin{ []{ return std::make_unique< ExportPCM >(); } };
|
||||
static Exporter::RegisteredExportPlugin sRegisteredPlugin{ "PCM",
|
||||
[]{ return std::make_unique< ExportPCM >(); }
|
||||
};
|
||||
|
@ -84,11 +84,33 @@ ImportPluginList &Importer::sImportPluginList()
|
||||
return theList;
|
||||
}
|
||||
|
||||
namespace {
|
||||
static const auto PathStart = wxT("Importers");
|
||||
|
||||
static Registry::GroupItem &sRegistry()
|
||||
{
|
||||
static Registry::TransparentGroupItem<> registry{ PathStart };
|
||||
return registry;
|
||||
}
|
||||
|
||||
struct ImporterItem final : Registry::SingleItem {
|
||||
ImporterItem( const Identifier &id, std::unique_ptr<ImportPlugin> pPlugin )
|
||||
: SingleItem{ id }
|
||||
, mpPlugin{ std::move( pPlugin ) }
|
||||
{}
|
||||
|
||||
std::unique_ptr<ImportPlugin> mpPlugin;
|
||||
};
|
||||
}
|
||||
|
||||
Importer::RegisteredImportPlugin::RegisteredImportPlugin(
|
||||
std::unique_ptr<ImportPlugin> pPlugin )
|
||||
const Identifier &id,
|
||||
std::unique_ptr<ImportPlugin> pPlugin,
|
||||
const Registry::Placement &placement )
|
||||
{
|
||||
if ( pPlugin )
|
||||
sImportPluginList().emplace_back( std::move( pPlugin ) );
|
||||
Registry::RegisterItem( sRegistry(), placement,
|
||||
std::make_unique< ImporterItem >( id, std::move( pPlugin ) ) );
|
||||
}
|
||||
|
||||
UnusableImportPluginList &Importer::sUnusableImportPluginList()
|
||||
@ -110,16 +132,29 @@ bool Importer::Initialize()
|
||||
// order is significant. If none match, they will all be tried
|
||||
// in the order defined here.
|
||||
|
||||
// They were pushed on the array at static initialization time in an
|
||||
// unspecified sequence. Sort according to the sequence numbers they
|
||||
// report to make the order determinate.
|
||||
auto &list = sImportPluginList();
|
||||
std::sort( list.begin(), list.end(),
|
||||
[]( const ImportPluginList::value_type &a,
|
||||
const ImportPluginList::value_type &b ){
|
||||
return a->SequenceNumber() < b->SequenceNumber();
|
||||
using namespace Registry;
|
||||
static OrderingPreferenceInitializer init{
|
||||
PathStart,
|
||||
{ {wxT(""), wxT("PCM,OGG,FLAC,MP3,LOF,FFmpeg") } }
|
||||
// QT and GStreamer are only conditionally compiled and would get
|
||||
// placed at the end if present
|
||||
};
|
||||
|
||||
static struct MyVisitor final : Visitor {
|
||||
MyVisitor()
|
||||
{
|
||||
// Once only, visit the registry to collect the plug-ins properly
|
||||
// sorted
|
||||
TransparentGroupItem<> top{ PathStart };
|
||||
Registry::Visit( *this, &top, &sRegistry() );
|
||||
}
|
||||
);
|
||||
|
||||
void Visit( SingleItem &item, const Path &path ) override
|
||||
{
|
||||
sImportPluginList().push_back(
|
||||
static_cast<ImporterItem&>( item ).mpPlugin.get() );
|
||||
}
|
||||
} visitor;
|
||||
|
||||
// Ordering of the unusable plugin list is not important.
|
||||
|
||||
@ -292,7 +327,7 @@ void Importer::ReadImportItems()
|
||||
{
|
||||
if (importPlugin->GetPluginStringID() == new_item->filters[i])
|
||||
{
|
||||
new_item->filter_objects.push_back(importPlugin.get());
|
||||
new_item->filter_objects.push_back(importPlugin);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -307,7 +342,7 @@ void Importer::ReadImportItems()
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < new_item->filter_objects.size(); i++)
|
||||
{
|
||||
if (importPlugin.get() == new_item->filter_objects[i])
|
||||
if (importPlugin == new_item->filter_objects[i])
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@ -323,7 +358,7 @@ void Importer::ReadImportItems()
|
||||
new_item->filters.begin() + index,
|
||||
importPlugin->GetPluginStringID());
|
||||
new_item->filter_objects.insert(
|
||||
new_item->filter_objects.begin() + index, importPlugin.get());
|
||||
new_item->filter_objects.begin() + index, importPlugin);
|
||||
if (new_item->divider >= 0)
|
||||
new_item->divider++;
|
||||
}
|
||||
@ -402,7 +437,7 @@ std::unique_ptr<ExtImportItem> Importer::CreateDefaultImportItem()
|
||||
for (const auto &importPlugin : sImportPluginList())
|
||||
{
|
||||
new_item->filters.push_back(importPlugin->GetPluginStringID());
|
||||
new_item->filter_objects.push_back(importPlugin.get());
|
||||
new_item->filter_objects.push_back(importPlugin);
|
||||
}
|
||||
new_item->divider = -1;
|
||||
return new_item;
|
||||
@ -462,7 +497,7 @@ bool Importer::Import( AudacityProject &project,
|
||||
{
|
||||
// This plugin corresponds to user-selected filter, try it first.
|
||||
wxLogDebug(wxT("Inserting %s"),plugin->GetPluginStringID());
|
||||
importPlugins.insert(importPlugins.begin(), plugin.get());
|
||||
importPlugins.insert(importPlugins.begin(), plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -532,14 +567,14 @@ bool Importer::Import( AudacityProject &project,
|
||||
// is not changed by user selection overrides or any other mechanism, but we include an assert
|
||||
// in case subsequent code revisions to the constructor should break this assumption that
|
||||
// libsndfile is first.
|
||||
ImportPlugin *libsndfilePlugin = sImportPluginList().begin()->get();
|
||||
ImportPlugin *libsndfilePlugin = *sImportPluginList().begin();
|
||||
wxASSERT(libsndfilePlugin->GetPluginStringID() == wxT("libsndfile"));
|
||||
|
||||
for (const auto &plugin : sImportPluginList())
|
||||
{
|
||||
// Make sure its not already in the list
|
||||
if (importPlugins.end() ==
|
||||
std::find(importPlugins.begin(), importPlugins.end(), plugin.get()))
|
||||
std::find(importPlugins.begin(), importPlugins.end(), plugin))
|
||||
{
|
||||
if (plugin->SupportsExtension(extension))
|
||||
{
|
||||
@ -562,7 +597,7 @@ bool Importer::Import( AudacityProject &project,
|
||||
}
|
||||
}
|
||||
wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
|
||||
importPlugins.push_back(plugin.get());
|
||||
importPlugins.push_back(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -577,10 +612,10 @@ bool Importer::Import( AudacityProject &project,
|
||||
{
|
||||
// Make sure its not already in the list
|
||||
if (importPlugins.end() ==
|
||||
std::find(importPlugins.begin(), importPlugins.end(), plugin.get()))
|
||||
std::find(importPlugins.begin(), importPlugins.end(), plugin))
|
||||
{
|
||||
wxLogDebug(wxT("Appending %s"),plugin->GetPluginStringID());
|
||||
importPlugins.push_back(plugin.get());
|
||||
importPlugins.push_back(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "../widgets/wxPanelWrapper.h" // to inherit
|
||||
#include "../FileNames.h" // for FileType
|
||||
|
||||
#include "../commands/CommandManager.h" // for Registry::Placement
|
||||
|
||||
class wxArrayString;
|
||||
class wxListBox;
|
||||
class AudacityProject;
|
||||
@ -80,7 +82,10 @@ public:
|
||||
// Objects of this type are statically constructed in files implementing
|
||||
// subclasses of ImportPlugin
|
||||
struct RegisteredImportPlugin{
|
||||
RegisteredImportPlugin( std::unique_ptr<ImportPlugin> );
|
||||
RegisteredImportPlugin(
|
||||
const Identifier &id, // an internal string naming the plug-in
|
||||
std::unique_ptr<ImportPlugin>,
|
||||
const Registry::Placement &placement = { wxEmptyString, {} } );
|
||||
};
|
||||
|
||||
// Objects of this type are statically constructed in files, to identify
|
||||
|
@ -185,8 +185,6 @@ public:
|
||||
///! Probes the file and opens it if appropriate
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
///! Does acual import, returned by FFmpegImportPlugin::Open
|
||||
@ -335,12 +333,7 @@ std::unique_ptr<ImportFileHandle> FFmpegImportPlugin::Open(
|
||||
return std::move(handle);
|
||||
}
|
||||
|
||||
unsigned FFmpegImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "FFmpeg",
|
||||
std::make_unique< FFmpegImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -137,8 +137,6 @@ class FLACImportPlugin final : public ImportPlugin
|
||||
TranslatableString GetPluginFormatDescription() override;
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
|
||||
@ -334,12 +332,7 @@ std::unique_ptr<ImportFileHandle> FLACImportPlugin::Open(
|
||||
return std::move(handle);
|
||||
}
|
||||
|
||||
unsigned FLACImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "FLAC",
|
||||
std::make_unique< FLACImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ class ImportPlugin;
|
||||
class UnusableImportPlugin;
|
||||
|
||||
using ImportPluginList =
|
||||
std::vector< std::unique_ptr<ImportPlugin> >;
|
||||
std::vector< ImportPlugin * >;
|
||||
using UnusableImportPluginList =
|
||||
std::vector< std::unique_ptr<UnusableImportPlugin> >;
|
||||
|
||||
|
@ -249,8 +249,6 @@ public:
|
||||
///! Probes the file and opens it if appropriate
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const wxString &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@ -261,7 +259,8 @@ public:
|
||||
// Instantiate GStreamerImportPlugin and add to the list of known importers
|
||||
|
||||
static
|
||||
Importer::RegisteredImportPlugin{ []() -> std::unique_ptr< ImportPlugin > {
|
||||
Importer::RegisteredImportPlugin{ "GStreamer",
|
||||
[]() -> std::unique_ptr< ImportPlugin > {
|
||||
wxLogMessage(_TS("Audacity is built against GStreamer version %d.%d.%d-%d"),
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
@ -1152,11 +1151,6 @@ GStreamerImportFileHandle::Import(TrackFactory *trackFactory,
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
unsigned GStreamerImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 80;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Message handlers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -116,8 +116,6 @@ public:
|
||||
TranslatableString GetPluginFormatDescription() override;
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject *pProject) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
|
||||
@ -272,12 +270,7 @@ ProgressResult LOFImportFileHandle::Import(
|
||||
return ProgressResult::Success;
|
||||
}
|
||||
|
||||
unsigned LOFImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "LOF",
|
||||
std::make_unique< LOFImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -117,8 +117,6 @@ public:
|
||||
TranslatableString GetPluginFormatDescription() override;
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
class MP3ImportFileHandle final : public ImportFileHandle
|
||||
@ -257,12 +255,7 @@ ProgressResult MP3ImportFileHandle::Import(
|
||||
return privateData.updateResult;
|
||||
}
|
||||
|
||||
unsigned MP3ImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "MP3",
|
||||
std::make_unique< MP3ImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -91,8 +91,6 @@ public:
|
||||
TranslatableString GetPluginFormatDescription() override;
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
|
||||
@ -215,12 +213,7 @@ std::unique_ptr<ImportFileHandle> OggImportPlugin::Open(
|
||||
return std::make_unique<OggImportFileHandle>(filename, std::move(file), std::move(vorbisFile));
|
||||
}
|
||||
|
||||
unsigned OggImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "OGG",
|
||||
std::make_unique< OggImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -89,8 +89,6 @@ public:
|
||||
TranslatableString GetPluginFormatDescription() override;
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
};
|
||||
|
||||
|
||||
@ -192,12 +190,7 @@ std::unique_ptr<ImportFileHandle> PCMImportPlugin::Open(
|
||||
return std::make_unique<PCMImportFileHandle>(filename, std::move(file), info);
|
||||
}
|
||||
|
||||
unsigned PCMImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "PCM",
|
||||
std::make_unique< PCMImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -96,8 +96,6 @@ public:
|
||||
virtual std::unique_ptr<ImportFileHandle> Open(
|
||||
const FilePath &Filename, AudacityProject*) = 0;
|
||||
|
||||
virtual unsigned SequenceNumber() const = 0;
|
||||
|
||||
virtual ~ImportPlugin() { }
|
||||
|
||||
protected:
|
||||
|
@ -125,8 +125,6 @@ class QTImportPlugin final : public ImportPlugin
|
||||
std::unique_ptr<ImportFileHandle> Open(
|
||||
const wxString & Filename, AudacityProject*) override;
|
||||
|
||||
unsigned SequenceNumber() const override;
|
||||
|
||||
private:
|
||||
bool mInitialized;
|
||||
};
|
||||
@ -222,12 +220,7 @@ std::unique_ptr<ImportFileHandle> QTImportPlugin::Open(
|
||||
return std::make_unique<QTImportFileHandle>(Filename, theMovie);
|
||||
}
|
||||
|
||||
unsigned QTImportPlugin::SequenceNumber() const
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
static Importer::RegisteredImportPlugin registered{
|
||||
static Importer::RegisteredImportPlugin registered{ "QT",
|
||||
std::make_unique< QTImportPlugin >()
|
||||
};
|
||||
|
||||
|
@ -97,12 +97,16 @@ BatchPrefs::~BatchPrefs()
|
||||
|
||||
#if 0
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 190,
|
||||
PrefsPanel::Registration sAttachment{ "Batch",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew BatchPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::Before, "KeyConfig" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -423,7 +423,7 @@ bool DevicePrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 10,
|
||||
PrefsPanel::Registration sAttachment{ "Device",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -300,7 +300,7 @@ DirectoriesPrefsFactory() {
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 150,
|
||||
PrefsPanel::Registration sAttachment{ "Directories",
|
||||
DirectoriesPrefsFactory() };
|
||||
};
|
||||
|
||||
|
@ -251,7 +251,7 @@ bool EffectsPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 170,
|
||||
PrefsPanel::Registration sAttachment{ "Effects",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -827,11 +827,14 @@ void ExtImportPrefsDropTarget::OnLeave()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 120,
|
||||
PrefsPanel::Registration sAttachment{ "ExtImport",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew ExtImportPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Place as a lower level of the tree of pages:
|
||||
{ "ImportExport" }
|
||||
};
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ int ShowClippingPrefsID()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 60,
|
||||
PrefsPanel::Registration sAttachment{ "GUI",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -150,12 +150,11 @@ bool ImportExportPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 110,
|
||||
PrefsPanel::Registration sAttachment{ "ImportExport",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew ImportExportPrefs(parent, winid);
|
||||
},
|
||||
1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -890,7 +890,7 @@ KeyConfigPrefsFactory( const CommandID &name )
|
||||
};
|
||||
}
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 200,
|
||||
PrefsPanel::Registration sAttachment{ "KeyConfig",
|
||||
KeyConfigPrefsFactory()
|
||||
};
|
||||
}
|
||||
|
@ -263,12 +263,16 @@ bool LibraryPrefs::Commit()
|
||||
|
||||
#if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) || !defined(DISABLE_DYNAMIC_LOADING_LAME)
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 140,
|
||||
PrefsPanel::Registration sAttachment{ "Library",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew LibraryPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::Before, "Directories" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -303,12 +303,16 @@ bool MidiIOPrefs::Validate()
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 40,
|
||||
PrefsPanel::Registration sAttachment{ "MidiIO",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew MidiIOPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::After, "Recording" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -191,12 +191,16 @@ void ModulePrefs::SetModuleStatus(const FilePath &fname, int iStatus){
|
||||
|
||||
#ifdef EXPERIMENTAL_MODULE_PREFS
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 220,
|
||||
PrefsPanel::Registration sAttachment{ "Module",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew ModulePrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::After, "Mouse" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -223,7 +223,7 @@ bool MousePrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 210,
|
||||
PrefsPanel::Registration sAttachment{ "Mouse",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -183,7 +183,7 @@ bool PlaybackPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 20,
|
||||
PrefsPanel::Registration sAttachment{ "Playback",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "../AudioIOBase.h"
|
||||
#include "../Prefs.h"
|
||||
#include "../ShuttleGui.h"
|
||||
#include "../commands/CommandManager.h"
|
||||
|
||||
#include "PrefsPanel.h"
|
||||
|
||||
@ -452,46 +453,101 @@ int wxTreebookExt::SetSelection(size_t n)
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Entry{
|
||||
unsigned sequenceNumber;
|
||||
PrefsDialog::PrefsNode node;
|
||||
|
||||
bool operator < ( const Entry &other ) const
|
||||
{ return sequenceNumber < other.sequenceNumber; }
|
||||
};
|
||||
using Entries = std::vector< Entry >;
|
||||
Entries &Registry()
|
||||
struct PrefsItem final : Registry::ConcreteGroupItem<false> {
|
||||
PrefsPanel::Factory factory;
|
||||
bool expanded{ false };
|
||||
|
||||
PrefsItem( const wxString &name,
|
||||
const PrefsPanel::Factory &factory_, bool expanded_ )
|
||||
: ConcreteGroupItem<false>{ name }
|
||||
, factory{ factory_ }, expanded{ expanded_ }
|
||||
{}
|
||||
};
|
||||
|
||||
// Collects registry tree nodes into a vector, in preorder.
|
||||
struct PrefsItemVisitor final : Registry::Visitor {
|
||||
PrefsItemVisitor( PrefsDialog::Factories &factories_ )
|
||||
: factories{ factories_ }
|
||||
{
|
||||
static Entries result;
|
||||
return result;
|
||||
childCounts.push_back( 0 );
|
||||
}
|
||||
void BeginGroup( Registry::GroupItem &item, const Path & ) override
|
||||
{
|
||||
auto pItem = dynamic_cast<PrefsItem*>( &item );
|
||||
if (!pItem)
|
||||
return;
|
||||
indices.push_back( factories.size() );
|
||||
factories.emplace_back( pItem->factory, 0, pItem->expanded );
|
||||
++childCounts.back();
|
||||
childCounts.push_back( 0 );
|
||||
}
|
||||
void EndGroup( Registry::GroupItem &item, const Path & ) override
|
||||
{
|
||||
auto pItem = dynamic_cast<PrefsItem*>( &item );
|
||||
if (!pItem)
|
||||
return;
|
||||
auto &factory = factories[ indices.back() ];
|
||||
factory.nChildren = childCounts.back();
|
||||
childCounts.pop_back();
|
||||
indices.pop_back();
|
||||
}
|
||||
|
||||
PrefsDialog::Factories &factories;
|
||||
std::vector<size_t> childCounts;
|
||||
std::vector<size_t> indices;
|
||||
};
|
||||
|
||||
|
||||
const auto PathStart = wxT("Preferences");
|
||||
|
||||
}
|
||||
|
||||
PrefsPanel::Registration::Registration( unsigned sequenceNumber,
|
||||
const Factory &factory,
|
||||
unsigned nChildren,
|
||||
bool expanded )
|
||||
|
||||
namespace {
|
||||
static Registry::GroupItem &sRegistry()
|
||||
{
|
||||
auto ®istry = Registry();
|
||||
Entry entry{ sequenceNumber, { factory, nChildren, expanded } };
|
||||
const auto end = registry.end();
|
||||
// Find insertion point:
|
||||
auto iter = std::lower_bound( registry.begin(), end, entry );
|
||||
// There should not be duplicate sequence numbers:
|
||||
wxASSERT( iter == end || entry < *iter );
|
||||
registry.insert( iter, entry );
|
||||
static Registry::TransparentGroupItem<> registry{ PathStart };
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
||||
PrefsPanel::Registration::Registration( const wxString &name,
|
||||
const Factory &factory, bool expanded,
|
||||
const Registry::Placement &placement )
|
||||
{
|
||||
Registry::RegisterItem( sRegistry(), placement,
|
||||
std::make_unique< PrefsItem >( name, factory, expanded ) );
|
||||
}
|
||||
|
||||
PrefsDialog::Factories
|
||||
&PrefsDialog::DefaultFactories()
|
||||
{
|
||||
// Once only, cause initial population of preferences for the ordering
|
||||
// of some preference pages that used to be given in a table but are now
|
||||
// separately registered in several .cpp files; the sequence of registration
|
||||
// depends on unspecified accidents of static initialization order across
|
||||
// compilation units, so we need something specific here to preserve old
|
||||
// default appearance of the preference dialog.
|
||||
// But this needs only to mention some strings -- there is no compilation or
|
||||
// link dependency of this source file on those other implementation files.
|
||||
static Registry::OrderingPreferenceInitializer init{
|
||||
PathStart,
|
||||
{
|
||||
{wxT(""),
|
||||
wxT("Device,Playback,Recording,Quality,GUI,Tracks,ImportExport,Directories,Warnings,Effects,KeyConfig,Mouse")
|
||||
},
|
||||
{wxT("/Tracks"), wxT("TracksBehaviors,Spectrum")},
|
||||
}
|
||||
};
|
||||
|
||||
static Factories factories;
|
||||
static std::once_flag flag;
|
||||
|
||||
std::call_once( flag, []{
|
||||
for ( const auto &entry : Registry() ) {
|
||||
factories.push_back( entry.node );
|
||||
}
|
||||
PrefsItemVisitor visitor{ factories };
|
||||
Registry::TransparentGroupItem<> top{ PathStart };
|
||||
Registry::Visit( visitor, &top, &sRegistry() );
|
||||
} );
|
||||
return factories;
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ class PrefsDialog /* not final */ : public wxDialogWrapper
|
||||
std::function< PrefsPanel * (
|
||||
wxWindow *parent, wxWindowID winid, AudacityProject *) >;
|
||||
Factory factory;
|
||||
unsigned nChildren;
|
||||
bool expanded;
|
||||
size_t nChildren{ 0 };
|
||||
bool expanded{ false };
|
||||
|
||||
PrefsNode(const Factory &factory_,
|
||||
unsigned nChildren_ = 0,
|
||||
|
@ -30,6 +30,7 @@ MousePrefs, QualityPrefs, SpectrumPrefs and ThemePrefs.
|
||||
#include <functional>
|
||||
#include "../widgets/wxPanelWrapper.h" // to inherit
|
||||
#include "../include/audacity/ComponentInterface.h"
|
||||
#include "../commands/CommandManager.h"
|
||||
|
||||
/* A few constants for an attempt at semi-uniformity */
|
||||
#define PREFS_FONT_SIZE 8
|
||||
@ -61,10 +62,9 @@ class PrefsPanel /* not final */ : public wxPanelWrapper, ComponentInterface
|
||||
// also implements the PrefsPanel subclass.
|
||||
struct Registration final
|
||||
{
|
||||
Registration( unsigned sequenceNumber,
|
||||
const Factory &factory,
|
||||
unsigned nChildren = 0,
|
||||
bool expanded = true );
|
||||
Registration( const wxString &name, const Factory &factory,
|
||||
bool expanded = true,
|
||||
const Registry::Placement &placement = { wxEmptyString, {} });
|
||||
};
|
||||
|
||||
PrefsPanel(wxWindow * parent,
|
||||
|
@ -99,12 +99,16 @@ bool ProjectsPrefs::Commit()
|
||||
|
||||
#ifdef EXPERIMENTAL_OD_DATA
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 130,
|
||||
PrefsPanel::Registration sAttachment{ "Projects",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew ProjectsPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::After, "ImportExport" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -234,7 +234,7 @@ bool QualityPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 50,
|
||||
PrefsPanel::Registration sAttachment{ "Quality",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -305,7 +305,7 @@ void RecordingPrefs::OnToggleCustomName(wxCommandEvent & /* Evt */)
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 30,
|
||||
PrefsPanel::Registration sAttachment{ "Recording",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -602,8 +602,10 @@ SpectrumPrefsFactory( WaveTrack *wt )
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 100,
|
||||
PrefsPanel::Registration sAttachment{ "Spectrum",
|
||||
SpectrumPrefsFactory( nullptr ),
|
||||
false
|
||||
false,
|
||||
// Place it at a lower tree level
|
||||
{ "Tracks" }
|
||||
};
|
||||
}
|
||||
|
@ -233,12 +233,16 @@ bool ThemePrefs::Commit()
|
||||
|
||||
#ifdef EXPERIMENTAL_THEME_PREFS
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 180,
|
||||
PrefsPanel::Registration sAttachment{ "Theme",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew ThemePrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled
|
||||
{ "", { Registry::OrderingHint::After, "Effects" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -132,11 +132,14 @@ bool TracksBehaviorsPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 90,
|
||||
PrefsPanel::Registration sAttachment{ "TracksBehaviors",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew TracksBehaviorsPrefs(parent, winid);
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Place it at a lower tree level
|
||||
{ "Tracks" }
|
||||
};
|
||||
}
|
||||
|
@ -448,12 +448,11 @@ bool TracksPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 70,
|
||||
PrefsPanel::Registration sAttachment{ "Tracks",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
return safenew TracksPrefs(parent, winid);
|
||||
},
|
||||
2
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ bool WarningsPrefs::Commit()
|
||||
}
|
||||
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 160,
|
||||
PrefsPanel::Registration sAttachment{ "Warnings",
|
||||
[](wxWindow *parent, wxWindowID winid, AudacityProject *)
|
||||
{
|
||||
wxASSERT(parent); // to justify safenew
|
||||
|
@ -265,9 +265,12 @@ WaveformPrefsFactory(WaveTrack *wt)
|
||||
}
|
||||
#if 0
|
||||
namespace{
|
||||
PrefsPanel::Registration sAttachment{ 80,
|
||||
PrefsPanel::Registration sAttachment{ "Waveform",
|
||||
WaveformPrefsFactory( nullptr ),
|
||||
false
|
||||
false,
|
||||
// Register with an explicit ordering hint because this one is
|
||||
// only conditionally compiled; and place it at a lower tree level
|
||||
{ "Tracks", { Registry::OrderingHint::Before, "Spectrum" } }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user