Reimplement ShuttleGui Tie... functions for radios and choices...

... so that in all cases a ChoiceSetting object stores all the details about
visible names, internal string codes, default value, and preference path.

Repetition of literals for some preference paths and their default values is
eliminated
This commit is contained in:
Paul Licameli 2019-11-26 12:11:07 -05:00
commit 1b5c5a52d2
53 changed files with 1242 additions and 1182 deletions

View File

@ -576,12 +576,12 @@ bool MacroCommands::WriteMp3File( const wxString & Name, int bitrate )
bool rc;
long prevBitRate = gPrefs->Read(wxT("/FileFormats/MP3Bitrate"), 128);
gPrefs->Write(wxT("/FileFormats/MP3Bitrate"), bitrate);
int prevMode = gPrefs->Read(wxT("/FileFormats/MP3RateMode"), MODE_CBR);
gPrefs->Write(wxT("/FileFormats/MP3RateMode"), MODE_CBR);
auto prevMode = MP3RateModeSetting.ReadEnum();
MP3RateModeSetting.WriteEnum(MODE_CBR);
auto cleanup = finally( [&] {
gPrefs->Write(wxT("/FileFormats/MP3Bitrate"), prevBitRate);
gPrefs->Write(wxT("/FileFormats/MP3RateMode"), prevMode);
MP3RateModeSetting.WriteEnum(prevMode);
gPrefs->Flush();
} );

View File

@ -52,6 +52,7 @@ AliasedFile s.
#include "blockfile/SimpleBlockFile.h"
#include "DirManager.h"
#include "FileFormats.h"
#include "Prefs.h"
#include "Project.h"
#include "ProjectSettings.h"
@ -589,8 +590,7 @@ void DependencyDialog::SaveFutureActionChoice()
case 2: savePref = wxT("never"); break;
default: savePref = wxT("ask");
}
gPrefs->Write(wxT("/FileFormats/SaveProjectWithDependencies"),
savePref);
FileFormatsSaveWithDependenciesSetting.Write( savePref );
gPrefs->Flush();
}
}
@ -632,9 +632,7 @@ New projects will be self-contained and are less risky.");
{
#ifdef EXPERIMENTAL_OD_DATA
wxString action =
gPrefs->Read(
wxT("/FileFormats/SaveProjectWithDependencies"),
wxT("ask"));
FileFormatsSaveWithDependenciesSetting.Read();
if (action == wxT("copy"))
{
// User always wants to remove dependencies

View File

@ -397,49 +397,45 @@ inline float Dither::ShapedDither(float sample)
return result;
}
static const EnumValueSymbol choicesDither[] = {
static const std::initializer_list<EnumValueSymbol> choicesDither{
{ XO("None") },
{ XO("Rectangle") },
{ XO("Triangle") },
{ XO("Shaped") },
};
static const size_t nChoicesDither = WXSIZEOF( choicesDither );
static const int intChoicesDither[] = {
(int) DitherType::none,
(int) DitherType::rectangle,
(int) DitherType::triangle,
(int) DitherType::shaped,
static auto intChoicesDither = {
DitherType::none,
DitherType::rectangle,
DitherType::triangle,
DitherType::shaped,
};
static_assert(
nChoicesDither == WXSIZEOF( intChoicesDither ),
"size mismatch"
);
static const size_t defaultFastDither = 0; // none
EnumSetting Dither::FastSetting{
EnumSetting< DitherType > Dither::FastSetting{
wxT("Quality/DitherAlgorithmChoice"),
choicesDither, nChoicesDither, defaultFastDither,
choicesDither,
0, // none
// for migrating old preferences:
intChoicesDither,
wxT("Quality/DitherAlgorithm")
};
static const size_t defaultBestDither = 3; // shaped
EnumSetting Dither::BestSetting{
EnumSetting< DitherType > Dither::BestSetting{
wxT("Quality/HQDitherAlgorithmChoice"),
choicesDither, nChoicesDither, defaultBestDither,
choicesDither,
3, // shaped
// for migrating old preferences:
intChoicesDither,
wxT("Quality/HQDitherAlgorithm")
};
DitherType Dither::FastDitherChoice()
{
return (DitherType) FastSetting.ReadInt();
return (DitherType) FastSetting.ReadEnum();
}
DitherType Dither::BestDitherChoice()
{
return (DitherType) BestSetting.ReadInt();
return (DitherType) BestSetting.ReadEnum();
}

View File

@ -12,7 +12,7 @@
#include "audacity/Types.h" // for samplePtr
class EnumSetting;
template< typename Enum > class EnumSetting;
/// These ditherers are currently available:
@ -25,7 +25,7 @@ public:
static DitherType FastDitherChoice();
static DitherType BestDitherChoice();
static EnumSetting FastSetting, BestSetting;
static EnumSetting< DitherType > FastSetting, BestSetting;
/// Default constructor
Dither();

View File

@ -23,6 +23,7 @@ information.
#include "sndfile.h"
#include "Internat.h"
#include "widgets/AudacityMessageBox.h"
#include "Prefs.h"
#ifndef SNDFILE_1
#error Requires libsndfile 1.0 or higher
@ -334,3 +335,28 @@ int SFFileCloser::operator() (SNDFILE *sf) const
}
return err;
}
ChoiceSetting FileFormatsCopyOrEditSetting{
wxT("/FileFormats/CopyOrEditUncompressedData"),
{
EnumValueSymbol{
wxT("copy"),
XO("&Copy uncompressed files into the project (safer)")
},
EnumValueSymbol{
wxT("edit"),
XO("&Read uncompressed files from original location (faster)")
},
},
0 // copy
};
ChoiceSetting FileFormatsSaveWithDependenciesSetting{
wxT("/FileFormats/SaveProjectWithDependencies"),
{
{ wxT("copy"), XO("&Copy all audio into project (safest)") },
{ wxT("never"), XO("Do &not copy any audio") },
{ wxT("ask"), XO("As&k") },
},
2 // ask
};

View File

@ -17,6 +17,7 @@
#include "sndfile.h"
class ChoiceSetting;
class wxString;
//
@ -130,4 +131,7 @@ struct SFFile : public std::unique_ptr<SNDFILE, ::SFFileCloser>
}
};
extern ChoiceSetting FileFormatsCopyOrEditSetting;
extern ChoiceSetting FileFormatsSaveWithDependenciesSetting;
#endif

View File

@ -360,7 +360,7 @@ void MixerTrackCluster::UpdatePrefs()
{
this->SetBackgroundColour( theTheme.Colour( clrMedium ) );
mStaticText_TrackName->SetForegroundColour(theTheme.Colour(clrTrackPanelText));
HandleResize(); // in case prefs "/GUI/Solo" changed
HandleResize(); // in case TracksBehaviorsSolo changed
}
#endif

View File

@ -34,6 +34,7 @@
#include "DirManager.h"
#include "Prefs.h"
#include "ProjectFileIORegistry.h"
#include "prefs/ImportExportPrefs.h"
#include "InconsistencyException.h"
@ -847,8 +848,7 @@ bool NoteTrack::ExportMIDI(const wxString &f) const
bool NoteTrack::ExportAllegro(const wxString &f) const
{
double offset = GetOffset();
bool in_seconds;
gPrefs->Read(wxT("/FileFormats/AllegroStyle"), &in_seconds, true);
auto in_seconds = ImportExportPrefs::AllegroStyleSetting.ReadEnum();
auto &seq = GetSeq();
if (in_seconds) {
seq.convert_to_seconds();

View File

@ -240,9 +240,58 @@ void FinishPreferences()
}
//////////
EnumValueSymbols::EnumValueSymbols(
ByColumns_t,
const wxArrayStringEx &msgids,
wxArrayStringEx internals
)
: mInternals( std::move( internals ) )
{
auto size = mInternals.size(), size2 = msgids.size();
if ( size != size2 ) {
wxASSERT( false );
size = std::min( size, size2 );
}
reserve( size );
auto iter1 = mInternals.begin();
auto iter2 = msgids.begin();
while( size-- )
emplace_back( *iter1++, *iter2++ );
}
const wxArrayStringEx &EnumValueSymbols::GetTranslations() const
{
if ( mTranslations.empty() )
mTranslations = transform_container<wxArrayStringEx>( *this,
std::mem_fn( &EnumValueSymbol::Translation ) );
return mTranslations;
}
const wxArrayStringEx &EnumValueSymbols::GetInternals() const
{
if ( mInternals.empty() )
mInternals = transform_container<wxArrayStringEx>( *this,
std::mem_fn( &EnumValueSymbol::Internal ) );
return mInternals;
}
//////////
const EnumValueSymbol &ChoiceSetting::Default() const
{
if ( mDefaultSymbol >= 0 && mDefaultSymbol < mSymbols.size() )
return mSymbols[ mDefaultSymbol ];
static EnumValueSymbol empty;
return empty;
}
wxString ChoiceSetting::Read() const
{
const auto &defaultValue = Default().Internal();
return ReadWithDefault( defaultValue );
}
wxString ChoiceSetting::ReadWithDefault( const wxString &defaultValue ) const
{
wxString value;
if ( !gPrefs->Read(mKey, &value, defaultValue) )
if (!mMigrated) {
@ -253,16 +302,17 @@ wxString ChoiceSetting::Read() const
// Remap to default if the string is not known -- this avoids surprises
// in case we try to interpret config files from future versions
auto index = Find( value );
if ( index >= mnSymbols )
if ( index >= mSymbols.size() )
value = defaultValue;
return value;
}
size_t ChoiceSetting::Find( const wxString &value ) const
{
auto start = GetSymbols().begin();
return size_t(
std::find( begin(), end(), EnumValueSymbol{ value, {} } )
- mSymbols );
std::find( start, GetSymbols().end(), EnumValueSymbol{ value, {} } )
- start );
}
void ChoiceSetting::Migrate( wxString &value )
@ -273,7 +323,7 @@ void ChoiceSetting::Migrate( wxString &value )
bool ChoiceSetting::Write( const wxString &value )
{
auto index = Find( value );
if (index >= mnSymbols)
if (index >= mSymbols.size())
return false;
auto result = gPrefs->Write( mKey, value );
@ -281,27 +331,65 @@ bool ChoiceSetting::Write( const wxString &value )
return result;
}
int EnumSetting::ReadInt() const
{
if (!mIntValues)
return 0;
EnumSettingBase::EnumSettingBase(
const wxString &key,
EnumValueSymbols symbols,
long defaultSymbol,
std::vector<int> intValues, // must have same size as symbols
const wxString &oldKey
)
: ChoiceSetting{ key, std::move( symbols ), defaultSymbol }
, mIntValues{ std::move( intValues ) }
, mOldKey{ oldKey }
{
auto size = mSymbols.size();
if( mIntValues.size() != size ) {
wxASSERT( false );
mIntValues.resize( size );
}
}
void ChoiceSetting::SetDefault( long value )
{
if ( value < (long)mSymbols.size() )
mDefaultSymbol = value;
else
wxASSERT( false );
}
int EnumSettingBase::ReadInt() const
{
auto index = Find( Read() );
wxASSERT( index < mnSymbols );
wxASSERT( index < mIntValues.size() );
return mIntValues[ index ];
}
size_t EnumSetting::FindInt( int code ) const
int EnumSettingBase::ReadIntWithDefault( int defaultValue ) const
{
if (!mIntValues)
return mnSymbols;
wxString defaultString;
auto index0 = FindInt( defaultValue );
if ( index0 < mSymbols.size() )
defaultString = mSymbols[ index0 ].Internal();
else
wxASSERT( false );
return size_t(
std::find( mIntValues, mIntValues + mnSymbols, code )
- mIntValues );
auto index = Find( ReadWithDefault( defaultString ) );
wxASSERT( index < mSymbols.size() );
return mIntValues[ index ];
}
void EnumSetting::Migrate( wxString &value )
size_t EnumSettingBase::FindInt( int code ) const
{
const auto start = mIntValues.begin();
return size_t(
std::find( start, mIntValues.end(), code )
- start );
}
void EnumSettingBase::Migrate( wxString &value )
{
int intValue = 0;
if ( !mOldKey.empty() &&
@ -310,19 +398,21 @@ void EnumSetting::Migrate( wxString &value )
// Do not DELETE the old key -- let that be read if user downgrades
// Audacity. But further changes will be stored only to the NEW key
// and won't be seen then.
auto index = FindInt( intValue );
if ( index >= mnSymbols )
auto index = (long) FindInt( intValue );
if ( index >= mSymbols.size() )
index = mDefaultSymbol;
value = mSymbols[index].Internal();
Write(value);
gPrefs->Flush();
if ( index >= 0 && index < mSymbols.size() ) {
value = mSymbols[index].Internal();
Write(value);
gPrefs->Flush();
}
}
}
bool EnumSetting::WriteInt( int code ) // you flush gPrefs afterward
bool EnumSettingBase::WriteInt( int code ) // you flush gPrefs afterward
{
auto index = FindInt( code );
if ( index >= mnSymbols )
if ( index >= mSymbols.size() )
return false;
return Write( mSymbols[index].Internal() );
}
@ -331,3 +421,5 @@ wxString WarningDialogKey(const wxString &internalDialogName)
{
return wxT("/Warnings/") + internalDialogName;
}
ByColumns_t ByColumns{};

View File

@ -32,6 +32,7 @@
#include "Audacity.h"
#include "../include/audacity/ComponentInterface.h"
#include "MemoryX.h" // for wxArrayStringEx
#include <memory>
#include <wx/fileconf.h> // to inherit wxFileConfig
@ -86,6 +87,38 @@ public:
int mVersionMicroKeyInit{};
};
struct ByColumns_t{};
extern ByColumns_t ByColumns;
/// A table of EnumValueSymbol that you can access by "row" with
/// operator [] but also allowing access to the "columns" of internal or
/// translated strings, and also allowing convenient column-wise construction
class EnumValueSymbols : public std::vector< EnumValueSymbol >
{
public:
EnumValueSymbols() = default;
EnumValueSymbols( std::initializer_list<EnumValueSymbol> symbols )
: vector( symbols )
{}
// columnwise constructor; arguments must have same size
// (Implicit constructor takes initial tag argument to avoid unintended
// overload resolution to the inherited constructor taking
// initializer_list, in the case that each column has exactly two strings)
EnumValueSymbols(
ByColumns_t,
const wxArrayStringEx &msgids, // untranslated!
wxArrayStringEx internals
);
const wxArrayStringEx &GetTranslations() const;
const wxArrayStringEx &GetInternals() const;
private:
mutable wxArrayStringEx mTranslations;
mutable wxArrayStringEx mInternals;
};
/// Packages a table of user-visible choices each with an internal code string,
/// a preference key path, and a default choice
class ChoiceSetting
@ -93,78 +126,122 @@ class ChoiceSetting
public:
ChoiceSetting(
const wxString &key,
const EnumValueSymbol symbols[], size_t nSymbols,
size_t defaultSymbol
EnumValueSymbols symbols,
long defaultSymbol = -1
)
: mKey{ key }
, mSymbols{ symbols }
, mnSymbols{ nSymbols }
, mSymbols{ std::move( symbols ) }
, mDefaultSymbol{ defaultSymbol }
{
wxASSERT( defaultSymbol < nSymbols );
wxASSERT( defaultSymbol < (long)mSymbols.size() );
}
const wxString &Key() const { return mKey; }
const EnumValueSymbol &Default() const
{ return mSymbols[mDefaultSymbol]; }
const EnumValueSymbol *begin() const { return mSymbols; }
const EnumValueSymbol *end() const { return mSymbols + mnSymbols; }
const EnumValueSymbol &Default() const;
const EnumValueSymbols &GetSymbols() const { return mSymbols; }
wxString Read() const;
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
wxString ReadWithDefault( const wxString & ) const;
bool Write( const wxString &value ); // you flush gPrefs afterward
void SetDefault( long value );
protected:
size_t Find( const wxString &value ) const;
virtual void Migrate( wxString& );
const wxString mKey;
const EnumValueSymbol *mSymbols;
const size_t mnSymbols;
const EnumValueSymbols mSymbols;
// stores an internal value
mutable bool mMigrated { false };
const size_t mDefaultSymbol;
long mDefaultSymbol;
};
/// Extends ChoiceSetting with a corresponding table of integer codes
/// (generally not equal to their table positions),
/// and optionally an old preference key path that stored integer codes, to be
/// migrated into one that stores internal string values instead
class EnumSetting : public ChoiceSetting
class EnumSettingBase : public ChoiceSetting
{
public:
EnumSetting(
EnumSettingBase(
const wxString &key,
const EnumValueSymbol symbols[], size_t nSymbols,
size_t defaultSymbol,
EnumValueSymbols symbols,
long defaultSymbol,
const int intValues[] = nullptr, // must have same size as symbols
const wxString &oldKey = wxString("")
)
: ChoiceSetting{ key, symbols, nSymbols, defaultSymbol }
, mIntValues{ intValues }
, mOldKey{ oldKey }
{
wxASSERT( mIntValues );
}
// Read and write the encoded values
virtual int ReadInt() const;
bool WriteInt( int code ); // you flush gPrefs afterward
std::vector<int> intValues, // must have same size as symbols
const wxString &oldKey
);
protected:
// Read and write the encoded values
int ReadInt() const;
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
int ReadIntWithDefault( int defaultValue ) const;
bool WriteInt( int code ); // you flush gPrefs afterward
size_t FindInt( int code ) const;
void Migrate( wxString& ) override;
private:
const int *mIntValues;
std::vector<int> mIntValues;
const wxString mOldKey;
};
/// Adapts EnumSettingBase to a particular enumeration type
template< typename Enum >
class EnumSetting : public EnumSettingBase
{
public:
EnumSetting(
const wxString &key,
EnumValueSymbols symbols,
long defaultSymbol,
std::initializer_list< Enum > values, // must have same size as symbols
const wxString &oldKey
)
: EnumSettingBase{
key, symbols, defaultSymbol,
{ values.begin(), values.end() },
oldKey
}
{}
// Wrap ReadInt() and ReadIntWithDefault() and WriteInt()
Enum ReadEnum() const
{ return static_cast<Enum>( ReadInt() ); }
// new direct use is discouraged but it may be needed in legacy code:
// use a default in case the preference is not defined, which may not be
// the default-default stored in this object.
Enum ReadEnumWithDefault( Enum defaultValue ) const
{
auto integer = static_cast<int>(defaultValue);
return static_cast<Enum>( ReadIntWithDefault( integer ) );
}
bool WriteEnum( Enum value )
{ return WriteInt( static_cast<int>( value ) ); }
};
// An event emitted by the application when the Preference dialog commits
// changes
wxDECLARE_EVENT(EVT_PREFS_UPDATE, wxCommandEvent);

View File

@ -22,6 +22,7 @@ Paul Licameli split from AudacityProject.cpp
#include "AutoRecovery.h"
#include "Dependencies.h"
#include "DirManager.h"
#include "FileFormats.h"
#include "FileNames.h"
#include "Legacy.h"
#include "PlatformCompatibility.h"
@ -122,13 +123,12 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
#ifdef EXPERIMENTAL_OD_DATA
// 'Lossless copy' projects have dependencies. We need to always copy-in
// these dependencies when converting to a normal project.
wxString oldAction =
gPrefs->Read(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy"));
auto oldAction = FileFormatsCopyOrEditSetting.Read();
bool oldAsk =
gPrefs->ReadBool(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), true);
if (oldAction != wxT("copy"))
gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy"));
FileFormatsCopyOrEditSetting.Write( wxT("copy") );
if (oldAsk)
gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) false);
gPrefs->Flush();
@ -136,7 +136,7 @@ auto ProjectFileManager::ReadProjectFile( const FilePath &fileName )
auto cleanup = finally( [&] {
// and restore old settings if necessary.
if (oldAction != wxT("copy"))
gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), oldAction);
FileFormatsCopyOrEditSetting.Write( oldAction );
if (oldAsk)
gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) true);
gPrefs->Flush();

View File

@ -16,6 +16,7 @@ Paul Licameli split from AudacityProject.cpp
#include "Project.h"
#include "prefs/QualityPrefs.h"
#include "widgets/NumericTextCtrl.h"
#include "prefs/TracksBehaviorsPrefs.h"
wxDEFINE_EVENT(EVT_PROJECT_SETTINGS_CHANGE, wxCommandEvent);
@ -91,7 +92,7 @@ void ProjectSettings::UpdatePrefs()
gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &mShowId3Dialog, true);
gPrefs->Read(wxT("/GUI/EmptyCanBeDirty"), &mEmptyCanBeDirty, true );
gPrefs->Read(wxT("/GUI/ShowSplashScreen"), &mShowSplashScreen, true);
gPrefs->Read(wxT("/GUI/Solo"), &mSoloPref, wxT("Simple"));
mSoloPref = TracksBehaviorsSolo.Read();
// Update the old default to the NEW default.
if (mSoloPref == wxT("Standard"))
mSoloPref = wxT("Simple");

View File

@ -52,53 +52,36 @@ Resample::~Resample()
}
//////////
static const EnumValueSymbol methodNames[] = {
static const std::initializer_list<EnumValueSymbol> methodNames{
{ wxT("LowQuality"), XO("Low Quality (Fastest)") },
{ wxT("MediumQuality"), XO("Medium Quality") },
{ wxT("HighQuality"), XO("High Quality") },
{ wxT("BestQuality"), XO("Best Quality (Slowest)") }
};
static const size_t numMethods = WXSIZEOF(methodNames);
static const wxString fastMethodKey =
wxT("/Quality/LibsoxrSampleRateConverterChoice");
static const wxString bestMethodKey =
wxT("/Quality/LibsoxrHQSampleRateConverterChoice");
static const wxString oldFastMethodKey =
wxT("/Quality/LibsoxrSampleRateConverter");
static const wxString oldBestMethodKey =
wxT("/Quality/LibsoxrHQSampleRateConverter");
static const size_t fastMethodDefault = 1; // Medium Quality
static const size_t bestMethodDefault = 3; // Best Quality
static const int intChoicesMethod[] = {
static auto intChoicesMethod = {
0, 1, 2, 3
};
static_assert( WXSIZEOF(intChoicesMethod) == numMethods, "size mismatch" );
EnumSetting Resample::FastMethodSetting{
fastMethodKey,
methodNames, numMethods,
fastMethodDefault,
EnumSetting< int > Resample::FastMethodSetting{
wxT("/Quality/LibsoxrSampleRateConverterChoice"),
methodNames,
1, // Medium Quality
// for migrating old preferences:
intChoicesMethod,
oldFastMethodKey
wxT("/Quality/LibsoxrSampleRateConverter")
};
EnumSetting Resample::BestMethodSetting
EnumSetting< int > Resample::BestMethodSetting
{
bestMethodKey,
methodNames, numMethods,
bestMethodDefault,
wxT("/Quality/LibsoxrHQSampleRateConverterChoice"),
methodNames,
3, // Best Quality,
// for migrating old preferences:
intChoicesMethod,
oldBestMethodKey
wxT("/Quality/LibsoxrHQSampleRateConverter")
};
//////////
@ -132,7 +115,7 @@ std::pair<size_t, size_t>
void Resample::SetMethod(const bool useBestMethod)
{
if (useBestMethod)
mMethod = BestMethodSetting.ReadInt();
mMethod = BestMethodSetting.ReadEnum();
else
mMethod = FastMethodSetting.ReadInt();
mMethod = FastMethodSetting.ReadEnum();
}

View File

@ -16,7 +16,7 @@
#include "SampleFormat.h"
class EnumSetting;
template< typename Enum > class EnumSetting;
struct soxr;
extern "C" void soxr_delete(soxr*);
@ -41,8 +41,8 @@ class Resample final
Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor);
~Resample();
static EnumSetting FastMethodSetting;
static EnumSetting BestMethodSetting;
static EnumSetting< int > FastMethodSetting;
static EnumSetting< int > BestMethodSetting;
/** @brief Main processing function. Resamples from the input buffer to the
* output buffer.

View File

@ -140,7 +140,7 @@ void ShuttleGuiBase::Init()
mpWind = NULL;
mpSubSizer = NULL;
mSettingName = wxT("");
mRadioSettingName = wxT("");
mRadioCount = -1;
miBorder = 5;
@ -483,33 +483,32 @@ wxComboBox * ShuttleGuiBase::AddCombo( const wxString &Prompt, const wxString &S
}
wxRadioButton * ShuttleGuiBase::AddRadioButton(const wxString &Prompt)
wxRadioButton * ShuttleGuiBase::DoAddRadioButton(
const wxString &Prompt, int style)
{
/// \todo This function and the next one, suitably adapted, could be
/// \todo This function and the next two, suitably adapted, could be
/// used by TieRadioButton.
UseUpId();
if( mShuttleMode != eIsCreating )
return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxRadioButton);
wxRadioButton * pRad;
mpWind = pRad = safenew wxRadioButton(GetParent(), miId, Prompt,
wxDefaultPosition, wxDefaultSize, Style( wxRB_GROUP ) );
wxDefaultPosition, wxDefaultSize, Style( style ) );
mpWind->SetName(wxStripMenuCodes(Prompt));
pRad->SetValue(true );
if ( style )
pRad->SetValue( true );
UpdateSizers();
return pRad;
}
wxRadioButton * ShuttleGuiBase::AddRadioButton(const wxString &Prompt)
{
return DoAddRadioButton( Prompt, wxRB_GROUP );
}
wxRadioButton * ShuttleGuiBase::AddRadioButtonToGroup(const wxString &Prompt)
{
UseUpId();
if( mShuttleMode != eIsCreating )
return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), wxRadioButton);
wxRadioButton * pRad;
mpWind = pRad = safenew wxRadioButton(GetParent(), miId, Prompt,
wxDefaultPosition, wxDefaultSize, Style( 0 ) );
mpWind->SetName(wxStripMenuCodes(Prompt));
UpdateSizers();
return pRad;
return DoAddRadioButton( Prompt, 0 );
}
#ifdef __WXMAC__
@ -1449,10 +1448,27 @@ wxChoice * ShuttleGuiBase::TieChoice(
return pChoice;
}
wxRadioButton * ShuttleGuiBase::TieRadioButton(const wxString &Prompt, WrappedType & WrappedRef)
/// This function must be within a StartRadioButtonGroup - EndRadioButtonGroup pair.
wxRadioButton * ShuttleGuiBase::TieRadioButton()
{
wxASSERT( mRadioCount >= 0); // Did you remember to use StartRadioButtonGroup() ?
EnumValueSymbol symbol;
if (mpRadioSetting && mRadioCount >= 0) {
const auto &symbols = mpRadioSetting->GetSymbols();
if ( mRadioCount < symbols.size() )
symbol = symbols[ mRadioCount ];
}
// In what follows, WrappedRef is used in read only mode, but we
// don't have a 'read-only' version, so we copy to deal with the constness.
auto Temp = symbol.Internal();
wxASSERT( !Temp.empty() ); // More buttons than values?
WrappedType WrappedRef( Temp );
mRadioCount++;
UseUpId();
wxRadioButton * pRadioButton = NULL;
@ -1460,10 +1476,18 @@ wxRadioButton * ShuttleGuiBase::TieRadioButton(const wxString &Prompt, WrappedTy
{
case eIsCreating:
{
const auto &Prompt = symbol.Translation();
mpWind = pRadioButton = safenew wxRadioButton(GetParent(), miId, Prompt,
wxDefaultPosition, wxDefaultSize,
(mRadioCount==1)?wxRB_GROUP:0);
pRadioButton->SetValue(WrappedRef.ValuesMatch( *mRadioValue ));
wxASSERT( WrappedRef.IsString() );
wxASSERT( mRadioValue->IsString() );
const bool value =
(WrappedRef.ReadAsString() == mRadioValue->ReadAsString() );
pRadioButton->SetValue( value );
pRadioButton->SetName(wxStripMenuCodes(Prompt));
UpdateSizers();
}
@ -1476,9 +1500,7 @@ wxRadioButton * ShuttleGuiBase::TieRadioButton(const wxString &Prompt, WrappedTy
pRadioButton = wxDynamicCast(pWnd, wxRadioButton);
wxASSERT( pRadioButton );
if( pRadioButton->GetValue() )
{
mRadioValue->WriteToAsWrappedType( WrappedRef );
}
mRadioValue->WriteToAsString( WrappedRef.ReadAsString() );
}
break;
default:
@ -1489,25 +1511,34 @@ wxRadioButton * ShuttleGuiBase::TieRadioButton(const wxString &Prompt, WrappedTy
}
/// Call this before any TieRadioButton calls.
/// This is the generic version and requires mRadioValue already initialised.
/// Versions for specific types must do that initialisation.
void ShuttleGuiBase::StartRadioButtonGroup( const wxString & SettingName )
void ShuttleGuiBase::StartRadioButtonGroup( const ChoiceSetting &Setting )
{
wxASSERT( mRadioValue && mRadioValue->eWrappedType != eWrappedNotSet );
mSettingName = SettingName;
mpRadioSetting = &Setting;
// Configure the generic type mechanism to use OUR string.
mRadioValueString = Setting.Default().Internal();
mRadioValue.create( mRadioValueString );
// Now actually start the radio button group.
mRadioSettingName = Setting.Key();
mRadioCount = 0;
if( mShuttleMode == eIsCreating )
DoDataShuttle( SettingName, *mRadioValue );
DoDataShuttle( Setting.Key(), *mRadioValue );
}
/// Call this after any TieRadioButton calls.
/// It's generic too. We don't need type-specific ones.
void ShuttleGuiBase::EndRadioButtonGroup()
{
// too few buttons?
wxASSERT( mRadioCount == mpRadioSetting->GetSymbols().size() );
if( mShuttleMode == eIsGettingFromDialog )
DoDataShuttle( mSettingName, *mRadioValue );
DoDataShuttle( mRadioSettingName, *mRadioValue );
mRadioValue.reset();// Clear it out...
mRadioSettingName = wxT("");
mRadioCount = -1; // So we detect a problem.
mpRadioSetting = nullptr;
}
//-----------------------------------------------------------------------//
@ -1648,30 +1679,6 @@ wxString ShuttleGuiBase::TranslateFromIndex( const int nIn, const wxArrayStringE
return wxT("");
}
/// Int-to-Index (choices can be items like e.g 0x400120 )
int ShuttleGuiBase::TranslateToIndex( const int Value, const std::vector<int> &Choices )
{
int n = make_iterator_range(Choices).index( Value );
if( n == wxNOT_FOUND )
n=miNoMatchSelector;
miNoMatchSelector = 0;
return n;
}
/// Index-to-int (choices can be items like e.g 0x400120 )
int ShuttleGuiBase::TranslateFromIndex( const int nIn, const std::vector<int> &Choices )
{
int n = nIn;
if( n== wxNOT_FOUND )
n=miNoMatchSelector;
miNoMatchSelector = 0;
if( n < (int)Choices.size() )
{
return Choices[n];
}
return 0;
}
//-----------------------------------------------------------------------//
@ -1861,35 +1868,17 @@ wxTextCtrl * ShuttleGuiBase::TieNumericTextBox(
/// those as default.
wxChoice *ShuttleGuiBase::TieChoice(
const wxString &Prompt,
ChoiceSetting &choiceSetting )
const ChoiceSetting &choiceSetting )
{
// Do this to force any needed migrations first
choiceSetting.Read();
wxArrayStringEx visibleChoices, internalChoices;
for (const auto &ident : choiceSetting) {
visibleChoices.push_back( ident.Translation() );
internalChoices.push_back( ident.Internal() );
}
return TieChoice(
Prompt, choiceSetting.Key(), choiceSetting.Default().Internal(),
visibleChoices, internalChoices );
}
const auto &symbols = choiceSetting.GetSymbols();
const auto &SettingName = choiceSetting.Key();
const auto &Default = choiceSetting.Default().Internal();
const auto &Choices = symbols.GetTranslations();
const auto &InternalChoices = symbols.GetInternals();
/// Variant of the standard TieChoice which does the two step exchange
/// between gui and stack variable and stack variable and shuttle.
/// @param Prompt The prompt shown beside the control.
/// @param SettingName The setting name as stored in gPrefs
/// @param Default The default value for this control (translated)
/// @param Choices An array of choices that appear on screen.
/// @param InternalChoices The corresponding values (as a string array)
wxChoice * ShuttleGuiBase::TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const wxString &Default,
const wxArrayStringEx & Choices,
const wxArrayStringEx & InternalChoices)
{
wxChoice * pChoice=(wxChoice*)NULL;
int TempIndex=0;
@ -1900,43 +1889,14 @@ wxChoice * ShuttleGuiBase::TieChoice(
// Put to prefs does 2 and 3.
if( DoStep(1) ) DoDataShuttle( SettingName, WrappedRef ); // Get Index from Prefs.
if( DoStep(1) ) TempIndex = TranslateToIndex( TempStr, InternalChoices ); // To an index
if( DoStep(2) ) pChoice = TieChoice( Prompt, TempIndex, Choices ); // Get/Put index from GUI.
if( DoStep(2) )
pChoice = TieChoice( Prompt, TempIndex,
transform_container<wxArrayStringEx>(Choices, GetCustomTranslation) );
if( DoStep(3) ) TempStr = TranslateFromIndex( TempIndex, InternalChoices ); // To a string
if( DoStep(3) ) DoDataShuttle( SettingName, WrappedRef ); // Put into Prefs.
return pChoice;
}
/// Variant of the standard TieChoice which does the two step exchange
/// between gui and stack variable and stack variable and shuttle.
/// Difference to previous one is that the Translated choices and default
/// are integers, not Strings.
/// @param Prompt The prompt shown beside the control.
/// @param SettingName The setting name as stored in gPrefs
/// @param Default The default value for this control (translated)
/// @param Choices An array of choices that appear on screen.
/// @param InternalChoices The corresponding values (as an integer array)
wxChoice * ShuttleGuiBase::TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices)
{
wxChoice * pChoice=(wxChoice*)NULL;
int TempIndex=0;
int TranslatedInt = Default;
WrappedType WrappedRef( TranslatedInt );
// Get from prefs does 1 and 2.
// Put to prefs does 2 and 3.
if( DoStep(1) ) DoDataShuttle( SettingName, WrappedRef ); // Get Int from Prefs.
if( DoStep(1) ) TempIndex = TranslateToIndex( TranslatedInt, InternalChoices ); // Int to an index.
if( DoStep(2) ) pChoice = TieChoice( Prompt, TempIndex, Choices ); // Get/Put index from GUI.
if( DoStep(3) ) TranslatedInt = TranslateFromIndex( TempIndex, InternalChoices ); // Index to int
if( DoStep(3) ) DoDataShuttle( SettingName, WrappedRef ); // Put into Prefs.
return pChoice;
}
/// Variant of the standard TieChoice which does the two step exchange
/// between gui and stack variable and stack variable and shuttle.
/// The Translated choices and default are integers, not Strings.
@ -1944,63 +1904,46 @@ wxChoice * ShuttleGuiBase::TieChoice(
/// are non-exhaustive and there is a companion control for abitrary entry.
/// @param Prompt The prompt shown beside the control.
/// @param SettingName The setting name as stored in gPrefs
/// @param Default The default value for this control (translated)
/// @param Default The default integer value for this control
/// @param Choices An array of choices that appear on screen.
/// @param InternalChoices The corresponding values (as an integer array)
/// @param pInternalChoices The corresponding values (as an integer array)
/// if null, then use 0, 1, 2, ...
wxChoice * ShuttleGuiBase::TieNumberAsChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices)
const std::vector<int> * pInternalChoices)
{
return ShuttleGuiBase::TieChoice(
Prompt, SettingName, Default, Choices, InternalChoices );
}
auto fn = [](int arg){ return wxString::Format( "%d", arg ); };
/// Integer specific version of StartRadioButtonGroup.
/// All 'TieRadioButton()' enclosed must be ints.
void ShuttleGuiBase::StartRadioButtonGroup( const wxString & SettingName, const int iDefaultValue )
{
// Configure the generic type mechanism to use OUR integer.
mRadioValueInt = iDefaultValue;
mRadioValue.create( mRadioValueInt );
// Now actually start the radio button group.
StartRadioButtonGroup( SettingName );
}
wxArrayStringEx InternalChoices;
if ( pInternalChoices )
InternalChoices =
transform_container<wxArrayStringEx>(*pInternalChoices, fn);
else
for ( int ii = 0; ii < Choices.size(); ++ii )
InternalChoices.push_back( fn( ii ) );
/// String specific version of StartRadioButtonGroup.
/// All 'TieRadioButton()' enclosed must be strings.
void ShuttleGuiBase::StartRadioButtonGroup( const wxString & SettingName, const wxString & DefaultValue )
{
// Configure the generic type mechanism to use OUR string.
mRadioValueString = DefaultValue;
mRadioValue.create( mRadioValueString );
// Now actually start the radio button group.
StartRadioButtonGroup( SettingName );
}
long defaultIndex;
if ( pInternalChoices )
defaultIndex = make_iterator_range( *pInternalChoices ).index( Default );
else
defaultIndex = Default;
if ( defaultIndex < 0 || defaultIndex >= Choices.size() )
defaultIndex = -1;
ChoiceSetting Setting{
SettingName,
{
ByColumns,
Choices,
InternalChoices,
},
defaultIndex
};
/// This function must be within a StartRadioButtonGroup - EndRadioButtonGroup pair.
wxRadioButton * ShuttleGuiBase::TieRadioButton(
const wxString &Prompt,
const int iValue)
{
int iTemp = iValue;
WrappedType WrappedRef( iTemp );
return TieRadioButton( Prompt, WrappedRef );
}
/// This function must be within a StartRadioButtonGroup - EndRadioButtonGroup pair.
wxRadioButton * ShuttleGuiBase::TieRadioButton(
const wxString &Prompt,
const wxString &Value)
{
// In what follows, WrappedRef is used in read only mode, but we
// don't have a 'read-only' version, so we copy to deal with the constness.
wxString Temp = Value;
WrappedType WrappedRef( Temp );
return TieRadioButton( Prompt, WrappedRef );
return ShuttleGuiBase::TieChoice( Prompt, Setting );
}
//------------------------------------------------------------------//

View File

@ -175,19 +175,14 @@ public:
wxPanel * StartInvisiblePanel();
void EndInvisiblePanel();
void StartRadioButtonGroup( const wxString & SettingName );
void StartRadioButtonGroup( const ChoiceSetting &Setting );
void EndRadioButtonGroup();
void StartRadioButtonGroup( const wxString & SettingName, const int iDefaultValue );
void StartRadioButtonGroup( const wxString & SettingName, const wxString &DefaultValue );
void DoDataShuttle( const wxString &Name, WrappedType & WrappedRef );
bool DoStep( int iStep );
int TranslateToIndex( const wxString &Value, const wxArrayStringEx &Choices );
wxString TranslateFromIndex( const int nIn, const wxArrayStringEx &Choices );
int TranslateToIndex( const int Value, const std::vector<int> &Choices );
int TranslateFromIndex( const int nIn, const std::vector<int> &Choices );
//-- Tie functions both add controls and also read/write to them.
// The ones taking a 'WrappedType' are type-generic and are used by the type specific ones.
@ -216,9 +211,9 @@ public:
wxSlider * TieSlider( const wxString &Prompt, float &pos, const float fMin, const float fMax);
wxSlider * TieVSlider( const wxString &Prompt, float &pos, const float fMin, const float fMax);
wxRadioButton * TieRadioButton( const wxString & Prompt, WrappedType &WrappedRef);
wxRadioButton * TieRadioButton( const wxString &Prompt, const int iValue);
wxRadioButton * TieRadioButton( const wxString &Prompt, const wxString &Value);
// Must be called between a StartRadioButtonGroup / EndRadioButtonGroup pair,
// and as many times as there are values in the enumeration.
wxRadioButton * TieRadioButton();
wxSpinCtrl * TieSpinCtrl( const wxString &Prompt, WrappedType & WrappedRef, const int max, const int min = 0 );
wxSpinCtrl * TieSpinCtrl( const wxString &Prompt, int &Value, const int max, const int min = 0 );
@ -237,31 +232,12 @@ public:
const wxString &SettingName,
const bool bDefault);
// This one is defined in terms of the next and not virtual
virtual wxChoice *TieChoice(
const wxString &Prompt,
ChoiceSetting &choiceSetting );
virtual wxChoice * TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const wxString &Default,
const wxArrayStringEx &Choices,
const wxArrayStringEx & InternalChoices );
// This overload of TieChoice should no longer be used in Preferences!
// Some uses do remain in export settings dialogs.
virtual wxChoice * TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices );
const ChoiceSetting &choiceSetting );
// This overload presents what is really a numerical setting as a choice among
// commonly used values, but the choice is not exhaustive because there is
// also an associated control that allows entry of a user-specified value
// that is arbitrary (within some bounds).
// commonly used values, but the choice is not necessarily exhaustive.
// This behaves just like the previous for building dialogs, but the
// behavior is different when the call is intercepted for purposes of
// emitting scripting information about Preferences.
@ -270,7 +246,7 @@ public:
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices );
const std::vector<int> * pInternalChoices = nullptr );
virtual wxTextCtrl * TieTextBox(
const wxString &Prompt,
@ -345,14 +321,6 @@ protected:
teShuttleMode mShuttleMode;
// These five are needed to handle radio button groups.
wxString mSettingName; /// The setting controlled by a group.
int mRadioCount; /// The index of this radio item. -1 for none.
Maybe<WrappedType> mRadioValue; /// The wrapped value associated with the active radio button.
wxString mRadioValueString; /// Unwrapped string value.
int mRadioValueInt; /// Unwrapped integer value.
int miSizerProp;
int mSizerDepth;
int miBorder;
@ -374,6 +342,14 @@ protected:
wxWindow * mpWind;
wxMenuBar * mpMenuBar;
wxMenu * mpMenu;
private:
const ChoiceSetting *mpRadioSetting = nullptr;
wxString mRadioSettingName; /// The setting controlled by a group.
Maybe<WrappedType> mRadioValue; /// The wrapped value associated with the active radio button.
int mRadioCount; /// The index of this radio item. -1 for none.
wxString mRadioValueString; /// Unwrapped string value.
wxRadioButton * DoAddRadioButton(const wxString &Prompt, int style);
};
// A rarely used helper function that sets a pointer

View File

@ -77,6 +77,7 @@ can't be.
#include "Prefs.h"
#include "ImageManipulation.h"
#include "Internat.h"
#include "prefs/GUIPrefs.h"
#include "widgets/AudacityMessageBox.h"
// JKC: First get the MAC specific images.
@ -234,11 +235,7 @@ void Theme::EnsureInitialised()
bool ThemeBase::LoadPreferredTheme()
{
// DA: Default themes differ.
#ifdef EXPERIMENTAL_DA
wxString theme = gPrefs->Read(wxT("/GUI/Theme"), wxT("dark"));
#else
wxString theme = gPrefs->Read(wxT("/GUI/Theme"), wxT("light"));
#endif
auto theme = GUITheme.Read();
theTheme.LoadTheme( theTheme.ThemeTypeOfTypeName( theme ) );
return true;

View File

@ -40,9 +40,9 @@ Paul Licameli split from TrackPanel.cpp
#include "Track.h"
#include "TrackPanelDrawingContext.h"
#include "ViewInfo.h"
#include "prefs/TracksBehaviorsPrefs.h"
#include "tracks/ui/TrackView.h"
// Subscribe to preference changes to update static variables
struct Settings : PrefsListener {
wxString gSoloPref;
@ -52,7 +52,7 @@ struct Settings : PrefsListener {
void UpdatePrefs() override
{
gPrefs->Read(wxT("/GUI/Solo"), &gSoloPref, wxT("Simple"));
gSoloPref = TracksBehaviorsSolo.Read();
// Calculation of best font size depends on language, so it should be redone in case
// the language preference changed.

View File

@ -37,62 +37,6 @@ bool WrappedType::IsString()
return eWrappedType == eWrappedString;
}
/// @param W Wrapped type to compare
/// @return true iff types and values are the same.
bool WrappedType::ValuesMatch( const WrappedType & W )
{
if( W.eWrappedType != eWrappedType )
return false;
switch( eWrappedType )
{
case eWrappedString:
return *W.mpStr == *mpStr;
break;
case eWrappedInt:
return *W.mpInt == *mpInt;
break;
case eWrappedDouble:
return *W.mpDouble == *mpDouble;
break;
case eWrappedBool:
return *W.mpBool == *mpBool;
break;
case eWrappedEnum:
wxASSERT( false );
break;
default:
wxASSERT( false );
break;
}
return false;
}
void WrappedType::WriteToAsWrappedType( const WrappedType & W )
{
wxASSERT( W.eWrappedType == eWrappedType );
switch( eWrappedType )
{
case eWrappedString:
*mpStr = *W.mpStr;
break;
case eWrappedInt:
*mpInt = *W.mpInt;
break;
case eWrappedDouble:
*mpDouble = *W.mpDouble;
break;
case eWrappedBool:
*mpBool = *W.mpBool;
break;
case eWrappedEnum:
wxASSERT( false );
break;
default:
wxASSERT( false );
break;
}
}
wxString WrappedType::ReadAsString()

View File

@ -59,9 +59,6 @@ public:
void WriteToAsDouble( const double InDouble);
void WriteToAsBool( const bool InBool);
bool ValuesMatch( const WrappedType & W );
void WriteToAsWrappedType( const WrappedType & W );
public :
const teWrappedType eWrappedType;

View File

@ -206,27 +206,13 @@ public:
const wxString &Prompt,
const wxString &SettingName,
const bool bDefault) override;
wxChoice * TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const wxString &Default,
const wxArrayStringEx &Choices,
const wxArrayStringEx & InternalChoices ) override;
// An assertion will be violated if this override is reached!
wxChoice * TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices) override;
wxChoice * TieNumberAsChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices) override;
const std::vector<int> * pInternalChoices) override;
wxTextCtrl * TieTextBox(
const wxString &Prompt,
@ -289,61 +275,12 @@ wxCheckBox * ShuttleGuiGetDefinition::TieCheckBoxOnRight(
EndStruct();
return ShuttleGui::TieCheckBoxOnRight( Prompt, SettingName, bDefault );
}
wxChoice * ShuttleGuiGetDefinition::TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const wxString &Default,
const wxArrayStringEx &Choices,
const wxArrayStringEx & InternalChoices )
{
StartStruct();
AddItem( SettingName, "id" );
AddItem( Prompt, "prompt" );
AddItem( "enum", "type" );
AddItem( Default, "default" );
StartField( "enum" );
StartArray();
for( size_t i=0;i<Choices.size(); i++ )
AddItem( InternalChoices[i] );
EndArray();
EndField();
EndStruct();
return ShuttleGui::TieChoice( Prompt, SettingName, Default, Choices, InternalChoices );
}
wxChoice * ShuttleGuiGetDefinition::TieChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices)
{
// Should no longer come here!
// Choice controls in Preferences that really are exhaustive choices among
// non-numerical options must now encode the internal choices as strings,
// not numbers.
wxASSERT(false);
// But if we do get here anyway, proceed sub-optimally as before.
StartStruct();
AddItem( SettingName, "id" );
AddItem( Prompt, "prompt" );
AddItem( "enum", "type" );
AddItem( Default, "default" );
StartField( "enum" );
StartArray();
for( size_t i=0;i<Choices.size(); i++ )
AddItem( Choices[i] );
EndArray();
EndField();
EndStruct();
return ShuttleGui::TieChoice( Prompt, SettingName, Default, Choices, InternalChoices );
}
wxChoice * ShuttleGuiGetDefinition::TieNumberAsChoice(
const wxString &Prompt,
const wxString &SettingName,
const int Default,
const wxArrayStringEx & Choices,
const std::vector<int> & InternalChoices)
const std::vector<int> * pInternalChoices)
{
// Come here for controls that present non-exhaustive choices among some
// numbers, with an associated control that allows arbitrary entry of an
@ -355,7 +292,7 @@ wxChoice * ShuttleGuiGetDefinition::TieNumberAsChoice(
AddItem( Default, "default" );
EndStruct();
return ShuttleGui::TieNumberAsChoice(
Prompt, SettingName, Default, Choices, InternalChoices );
Prompt, SettingName, Default, Choices, pInternalChoices );
}
wxTextCtrl * ShuttleGuiGetDefinition::TieTextBox(
const wxString &Prompt,

View File

@ -55,6 +55,7 @@
#include "../FileFormats.h"
#include "../Mix.h"
#include "../Prefs.h"
#include "../prefs/ImportExportPrefs.h"
#include "../Project.h"
#include "../ProjectHistory.h"
#include "../ProjectSettings.h"
@ -152,11 +153,16 @@ wxString ExportPlugin::GetFormat(int index)
return mFormatInfos[index].mFormat;
}
wxString ExportPlugin::GetDescription(int index)
wxString ExportPlugin::GetUntranslatedDescription(int index)
{
return mFormatInfos[index].mDescription;
}
wxString ExportPlugin::GetTranslatedDescription(int index)
{
return GetCustomTranslation( GetUntranslatedDescription( index ) );
}
FileExtension ExportPlugin::GetExtension(int index)
{
return mFormatInfos[index].mExtensions[0];
@ -173,7 +179,7 @@ wxString ExportPlugin::GetMask(int index)
return mFormatInfos[index].mMask;
}
wxString mask = GetDescription(index) + wxT("|");
wxString mask = GetTranslatedDescription(index) + wxT("|");
// Build the mask
// const auto &ext = GetExtension(index);
@ -847,7 +853,7 @@ bool Exporter::CheckMix()
// Detemine if exported file will be stereo or mono or multichannel,
// and if mixing will occur.
int downMix = gPrefs->Read(wxT("/FileFormats/ExportDownMix"), true);
auto downMix = ImportExportPrefs::ExportDownMixSetting.ReadEnum();
int exportedChannels = mPlugins[mFormat]->SetNumExportChannels();
if (downMix) {

View File

@ -45,7 +45,7 @@ class AUDACITY_DLL_API FormatInfo
~FormatInfo() {}
wxString mFormat;
wxString mDescription;
wxString mDescription; // untranslated
// wxString mExtension;
FileExtensions mExtensions;
wxString mMask;
@ -65,7 +65,7 @@ public:
int AddFormat();
void SetFormat(const wxString & format, int index);
void SetDescription(const wxString & description, int index);
void SetDescription(const wxString & description /* untranslated */, int index);
void AddExtension(const wxString &extension,int index);
void SetExtensions(FileExtensions extensions, int index);
void SetMask(const wxString & mask, int index);
@ -74,7 +74,8 @@ public:
virtual int GetFormatCount();
virtual wxString GetFormat(int index);
virtual wxString GetDescription(int index);
wxString GetUntranslatedDescription(int index);
wxString GetTranslatedDescription(int index);
/** @brief Return the (first) file name extension for the sub-format.
* @param index The sub-format for which the extension is wanted */
virtual FileExtension GetExtension(int index = 0);

View File

@ -312,7 +312,7 @@ ExportCL::ExportCL()
AddExtension(wxT(""),0);
SetMaxChannels(255,0);
SetCanMetaData(false,0);
SetDescription(_("(external program)"),0);
SetDescription(XO("(external program)"),0);
}
ProgressResult ExportCL::Export(AudacityProject *project,

View File

@ -225,7 +225,7 @@ ExportFFmpeg::ExportFFmpeg()
}
SetMaxChannels(ExportFFmpegOptions::fmts[newfmt].maxchannels,fmtindex);
SetDescription(ExportFFmpegOptions::fmts[newfmt].Description(), fmtindex);
SetDescription(ExportFFmpegOptions::fmts[newfmt].description_, fmtindex);
int canmeta = ExportFFmpegOptions::fmts[newfmt].canmetadata;
if (canmeta && (canmeta == AV_CANMETA || canmeta <= avfver))

View File

@ -138,20 +138,61 @@ static const wxChar *FFmpegExportCtrlIDNames[] = {
// ExportFFmpegAC3Options Class
//----------------------------------------------------------------------------
// This initialises content for the static const member variables defined in
// ExportFFmpegDialogs.h (note no static keyword - important!)
const int ExportFFmpegAC3Options::iAC3BitRates[] = { 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000, 448000, 512000, 576000, 640000 };
namespace
{
const wxArrayStringEx AC3BitRateNames{
// i18n-hint kbps abbreviates "thousands of bits per second"
XO("32 kbps"),
XO("40 kbps"),
XO("48 kbps"),
XO("56 kbps"),
XO("64 kbps"),
XO("80 kbps"),
XO("96 kbps"),
XO("112 kbps"),
XO("128 kbps"),
XO("160 kbps"),
XO("192 kbps"),
XO("224 kbps"),
XO("256 kbps"),
XO("320 kbps"),
XO("384 kbps"),
XO("448 kbps"),
XO("512 kbps"),
XO("576 kbps"),
XO("640 kbps"),
};
const std::vector< int > AC3BitRateValues{
32000,
40000,
48000,
56000,
64000,
80000,
96000,
112000,
128000,
160000,
192000,
224000,
256000,
320000,
384000,
448000,
512000,
576000,
640000,
};
}
const int ExportFFmpegAC3Options::iAC3SampleRates[] = { 32000, 44100, 48000, 0 };
ExportFFmpegAC3Options::ExportFFmpegAC3Options(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
for (unsigned int i=0; i < (sizeof(iAC3BitRates)/sizeof(int)); i++)
{
mBitRateNames.push_back(wxString::Format(_("%i kbps"),iAC3BitRates[i]/1000));
mBitRateLabels.push_back(iAC3BitRates[i]);
}
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
@ -173,8 +214,13 @@ void ExportFFmpegAC3Options::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/AC3BitRate"),
160000, mBitRateNames, mBitRateLabels);
S.TieNumberAsChoice(
_("Bit Rate:"),
wxT("/FileFormats/AC3BitRate"),
160000,
AC3BitRateNames,
&AC3BitRateValues
);
}
S.EndMultiColumn();
}
@ -264,20 +310,40 @@ bool ExportFFmpegAACOptions::TransferDataFromWindow()
// ExportFFmpegAMRNBOptions Class
//----------------------------------------------------------------------------
namespace {
/// Bit Rates supported by libAMR-NB encoder
/// Sample Rate is always 8 kHz
int ExportFFmpegAMRNBOptions::iAMRNBBitRate[] =
{ 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200 };
const wxArrayStringEx AMRNBBitRateNames
{
// i18n-hint kbps abbreviates "thousands of bits per second"
XO("4.75 kbps"),
XO("5.15 kbps"),
XO("5.90 kbps"),
XO("6.70 kbps"),
XO("7.40 kbps"),
XO("7.95 kbps"),
XO("10.20 kbps"),
XO("12.20 kbps"),
};
const std::vector< int > AMRNBBitRateValues
{
4750,
5150,
5900,
6700,
7400,
7950,
10200,
12200,
};
}
ExportFFmpegAMRNBOptions::ExportFFmpegAMRNBOptions(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
for (unsigned int i=0; i < (sizeof(iAMRNBBitRate)/sizeof(int)); i++)
{
mBitRateNames.push_back(wxString::Format(_("%.2f kbps"),(float)iAMRNBBitRate[i]/1000));
mBitRateLabels.push_back(iAMRNBBitRate[i]);
}
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
@ -299,8 +365,13 @@ void ExportFFmpegAMRNBOptions::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/AMRNBBitRate"),
12200, mBitRateNames, mBitRateLabels);
S.TieNumberAsChoice(
_("Bit Rate:"),
wxT("/FileFormats/AMRNBBitRate"),
12200,
AMRNBBitRateNames,
&AMRNBBitRateValues
);
}
S.EndMultiColumn();
}
@ -335,20 +406,46 @@ bool ExportFFmpegAMRNBOptions::TransferDataFromWindow()
const int ExportFFmpegWMAOptions::iWMASampleRates[] =
{ 8000, 11025, 16000, 22050, 44100, 0};
namespace {
/// Bit Rates supported by WMA encoder. Setting bit rate to other values will not result in different file size.
const int ExportFFmpegWMAOptions::iWMABitRate[] =
{ 24000, 32000, 40000, 48000, 64000, 80000, 96000, 128000, 160000, 192000, 256000, 320000 };
const wxArrayStringEx WMABitRateNames
{
// i18n-hint kbps abbreviates "thousands of bits per second"
XO("24 kbps"),
XO("32 kbps"),
XO("40 kbps"),
XO("48 kbps"),
XO("64 kbps"),
XO("80 kbps"),
XO("96 kbps"),
XO("128 kbps"),
XO("160 kbps"),
XO("192 kbps"),
XO("256 kbps"),
XO("320 kbps"),
};
const std::vector< int > WMABitRateValues{
24000,
32000,
40000,
48000,
64000,
80000,
96000,
128000,
160000,
192000,
256000,
320000,
};
}
ExportFFmpegWMAOptions::ExportFFmpegWMAOptions(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
for (unsigned int i=0; i < (sizeof(iWMABitRate)/sizeof(int)); i++)
{
/* i18n-hint: abbreviates thousands of bits per second */
mBitRateNames.push_back(wxString::Format(_("%i kbps"),iWMABitRate[i]/1000));
mBitRateLabels.push_back(iWMABitRate[i]);
}
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
@ -370,8 +467,13 @@ void ExportFFmpegWMAOptions::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/WMABitRate"),
128000, mBitRateNames, mBitRateLabels);
S.TieNumberAsChoice(
_("Bit Rate:"),
wxT("/FileFormats/WMABitRate"),
128000,
WMABitRateNames,
&WMABitRateValues
);
}
S.EndMultiColumn();
}
@ -1215,36 +1317,17 @@ CompatibilityEntry ExportFFmpegOptions::CompatibilityList[] =
};
/// AAC profiles
int ExportFFmpegOptions::iAACProfileValues[] = {
FF_PROFILE_AAC_LOW,
FF_PROFILE_AAC_MAIN,
/*FF_PROFILE_AAC_SSR,*/
FF_PROFILE_AAC_LTP
};
/// Names of AAC profiles to be displayed
static wxString iAACProfileNames(int index)
{
static const wxString names[] = {
XO("LC"),
XO("Main"),
/*_("SSR"),*/ //SSR is not supported
XO("LTP")
};
class NamesArray final : public TranslatableStringArray
// The FF_PROFILE_* enumeration is defined in the ffmpeg library
// PRL: I cant find where this preference is used!
ChoiceSetting AACProfiles { wxT("/FileFormats/FFmpegAACProfile"),
{
void Populate() override
{
for (auto &name : names)
mContents.push_back( wxGetTranslation( name ) );
}
};
static NamesArray theArray;
return theArray.Get()[ index ];
}
{wxT("1") /*FF_PROFILE_AAC_LOW*/, XO("LC")},
{wxT("0") /*FF_PROFILE_AAC_MAIN*/, XO("Main")},
// {wxT("2") /*FF_PROFILE_AAC_SSR*/, XO("SSR")}, //SSR is not supported
{wxT("3") /*FF_PROFILE_AAC_LTP*/, XO("LTP")},
},
0, // "1"
};
/// List of export types
ExposedFormat ExportFFmpegOptions::fmts[] =
@ -1349,30 +1432,18 @@ ApplicableFor ExportFFmpegOptions::apptable[] =
{FALSE,FFmpegExportCtrlID(0),AV_CODEC_ID_NONE,NULL}
};
/// Prediction order method - names. Labels are indices of this array.
static wxString PredictionOrderMethodNames(int index)
{
static const wxString names[] = {
XO("Estimate"),
XO("2-level"),
XO("4-level"),
XO("8-level"),
XO("Full search"),
XO("Log search")
};
namespace {
class NamesArray final : public TranslatableStringArray
{
void Populate() override
{
for (auto &name : names)
mContents.push_back( wxGetTranslation( name ) );
}
};
/// Prediction order method - names.
const wxArrayStringEx PredictionOrderMethodNames {
XO("Estimate"),
XO("2-level"),
XO("4-level"),
XO("8-level"),
XO("Full search"),
XO("Log search"),
};
static NamesArray theArray;
return theArray.Get()[ index ];
}
@ -1399,18 +1470,6 @@ ExportFFmpegOptions::ExportFFmpegOptions(wxWindow *parent)
FetchFormatList();
FetchCodecList();
for (unsigned int i = 0; i < 6; i++)
{
mPredictionOrderMethodLabels.push_back(i);
mPredictionOrderMethodNames.push_back(wxString::Format(wxT("%s"),PredictionOrderMethodNames(i)));
}
for (unsigned int i=0; i < (sizeof(iAACProfileValues)/sizeof(int)); i++)
{
mProfileNames.push_back(wxString::Format(wxT("%s"),iAACProfileNames(i)));
mProfileLabels.push_back(iAACProfileValues[i]);
}
PopulateOrExchange(S);
//Select the format that was selected last time this dialog was closed
@ -1549,8 +1608,8 @@ void ExportFFmpegOptions::PopulateOrExchange(ShuttleGui & S)
mCutoffSpin = S.Id(FECutoffID).TieSpinCtrl(_("Cutoff:"), wxT("/FileFormats/FFmpegCutOff"), 0, 10000000, 0);
mCutoffSpin->SetToolTip(_("Audio cutoff bandwidth (Hz)\nOptional\n0 - automatic"));
mProfileChoice = S.Id(FEProfileID).TieChoice(_("Profile:"), wxT("/FileFormats/FFmpegAACProfile"),
mProfileLabels[0], mProfileNames, mProfileLabels);
mProfileChoice = S.Id(FEProfileID)
.TieChoice(_("Profile:"), AACProfiles);
mProfileChoice->SetSizeHints( 100,-1);
mProfileChoice->SetToolTip(_("AAC Profile\nLow Complexity - default\nMost players won't play anything other than LC"));
@ -1571,8 +1630,13 @@ void ExportFFmpegOptions::PopulateOrExchange(ShuttleGui & S)
mLPCCoeffsPrecisionSpin = S.Id(FELPCCoeffsID).TieSpinCtrl(_("LPC"), wxT("/FileFormats/FFmpegLPCCoefPrec"), 0, 15, 0);
mLPCCoeffsPrecisionSpin->SetToolTip(_("LPC coefficients precision\nOptional\n0 - default\nmin - 1\nmax - 15"));
mPredictionOrderMethodChoice = S.Id(FEPredOrderID).TieChoice(_("PdO Method:"), wxT("/FileFormats/FFmpegPredOrderMethod"),
mPredictionOrderMethodLabels[4], mPredictionOrderMethodNames, mPredictionOrderMethodLabels);
mPredictionOrderMethodChoice = S.Id(FEPredOrderID)
.TieNumberAsChoice(
_("PdO Method:"),
wxT("/FileFormats/FFmpegPredOrderMethod"),
4, // Full search
PredictionOrderMethodNames
);
mPredictionOrderMethodChoice->SetSizeHints( 100,-1);
mPredictionOrderMethodChoice->SetToolTip(_("Prediction Order Method\nEstimate - fastest, lower compression\nLog search - slowest, best compression\nFull search - default"));

View File

@ -81,17 +81,12 @@ public:
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
/// Bit Rates supported by AC3 encoder
static const int iAC3BitRates[];
/// Sample Rates supported by AC3 encoder (must end with zero-element)
/// It is not used in dialog anymore, but will be required later
static const int iAC3SampleRates[];
private:
wxArrayStringEx mBitRateNames;
std::vector<int> mBitRateLabels;
wxChoice *mBitRateChoice;
int mBitRateFromChoice;
};
@ -123,13 +118,8 @@ public:
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
static int iAMRNBBitRate[];
private:
wxArrayStringEx mBitRateNames;
std::vector<int> mBitRateLabels;
wxChoice *mBitRateChoice;
int mBitRateFromChoice;
};
@ -146,13 +136,9 @@ public:
bool TransferDataFromWindow() override;
static const int iWMASampleRates[];
static const int iWMABitRate[];
private:
wxArrayStringEx mBitRateNames;
std::vector<int> mBitRateLabels;
wxChoice *mBitRateChoice;
int mBitRateFromChoice;
};
@ -212,7 +198,6 @@ public:
// Static tables
static CompatibilityEntry CompatibilityList[];
static int iAACProfileValues[];
static ExposedFormat fmts[];
static const int iAACSampleRates[];
static ApplicableFor apptable[];
@ -227,10 +212,6 @@ private:
wxArrayString mFormatLongNames;
wxArrayStringEx mCodecNames;
wxArrayString mCodecLongNames;
wxArrayStringEx mProfileNames;
std::vector<int> mProfileLabels;
wxArrayStringEx mPredictionOrderMethodNames;
std::vector<int> mPredictionOrderMethodLabels;
wxChoice *mFormatChoice;
wxChoice *mCodecChoice;

View File

@ -76,54 +76,58 @@ ExportFLACOptions::~ExportFLACOptions()
TransferDataFromWindow();
}
ChoiceSetting FLACBitDepth{
wxT("/FileFormats/FLACBitDepth"),
{
ByColumns,
{ XO("16 bit") , XO("24 bit") , },
{ wxT("16") , wxT("24") , }
},
0 // "16",
};
ChoiceSetting FLACLevel{
wxT("/FileFormats/FLACLevel"),
{
ByColumns,
{
XO("0 (fastest)") ,
XO("1") ,
XO("2") ,
XO("3") ,
XO("4") ,
XO("5") ,
XO("6") ,
XO("7") ,
XO("8 (best)") ,
},
{
wxT("0") ,
wxT("1") ,
wxT("2") ,
wxT("3") ,
wxT("4") ,
wxT("5") ,
wxT("6") ,
wxT("7") ,
wxT("8") ,
}
},
5 //"5"
};
///
///
void ExportFLACOptions::PopulateOrExchange(ShuttleGui & S)
{
wxArrayStringEx flacLevelLabels{
wxT("0") ,
wxT("1") ,
wxT("2") ,
wxT("3") ,
wxT("4") ,
wxT("5") ,
wxT("6") ,
wxT("7") ,
wxT("8") ,
};
wxArrayStringEx flacLevelNames{
_("0 (fastest)") ,
_("1") ,
_("2") ,
_("3") ,
_("4") ,
_("5") ,
_("6") ,
_("7") ,
_("8 (best)") ,
};
wxArrayStringEx flacBitDepthLabels{
wxT("16") ,
wxT("24") ,
};
wxArrayStringEx flacBitDepthNames{
_("16 bit") ,
_("24 bit") ,
};
S.StartVerticalLay();
{
S.StartHorizontalLay(wxCENTER);
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Level:"), wxT("/FileFormats/FLACLevel"),
wxT("5"), flacLevelNames, flacLevelLabels);
S.TieChoice(_("Bit depth:"), wxT("/FileFormats/FLACBitDepth"),
wxT("16"), flacBitDepthNames, flacBitDepthLabels);
S.TieChoice( _("Level:"), FLACLevel);
S.TieChoice( _("Bit depth:"), FLACBitDepth);
}
S.EndMultiColumn();
}
@ -239,7 +243,7 @@ ExportFLAC::ExportFLAC()
AddExtension(wxT("flac"),0);
SetMaxChannels(FLAC__MAX_CHANNELS,0);
SetCanMetaData(true,0);
SetDescription(_("FLAC Files"),0);
SetDescription(XO("FLAC Files"),0);
}
ProgressResult ExportFLAC::Export(AudacityProject *project,
@ -260,11 +264,10 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
wxLogNull logNo; // temporarily disable wxWidgets error messages
auto updateResult = ProgressResult::Success;
int levelPref;
gPrefs->Read(wxT("/FileFormats/FLACLevel"), &levelPref, 5);
long levelPref;
FLACLevel.Read().ToLong( &levelPref );
wxString bitDepthPref =
gPrefs->Read(wxT("/FileFormats/FLACBitDepth"), wxT("16"));
auto bitDepthPref = FLACBitDepth.Read();
FLAC::Encoder::File encoder;

View File

@ -75,12 +75,51 @@
// ExportMP2Options
//----------------------------------------------------------------------------
static int iBitrates[] = {
16, 24, 32, 40, 48, 56, 64,
80, 96, 112, 128, 160,
192, 224, 256, 320, 384
namespace {
const wxArrayStringEx BitRateNames {
// i18n-hint kbps abbreviates "thousands of bits per second"
XO("16 kbps"),
XO("24 kbps"),
XO("32 kbps"),
XO("40 kbps"),
XO("48 kbps"),
XO("56 kbps"),
XO("64 kbps"),
XO("80 kbps"),
XO("96 kbps"),
XO("112 kbps"),
XO("128 kbps"),
XO("160 kbps"),
XO("192 kbps"),
XO("224 kbps"),
XO("256 kbps"),
XO("320 kbps"),
XO("384 kbps"),
};
const std::vector< int > BitRateValues {
16,
24,
32,
40,
48,
56,
64,
80,
96,
112,
128,
160,
192,
224,
256,
320,
384,
};
}
class ExportMP2Options final : public wxPanelWrapper
{
public:
@ -90,10 +129,6 @@ public:
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
private:
wxArrayStringEx mBitRateNames;
std::vector<int> mBitRateLabels;
};
///
@ -101,12 +136,6 @@ private:
ExportMP2Options::ExportMP2Options(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
for (unsigned int i=0; i < (sizeof(iBitrates)/sizeof(int)); i++)
{
mBitRateNames.push_back(wxString::Format(_("%i kbps"),iBitrates[i]));
mBitRateLabels.push_back(iBitrates[i]);
}
ShuttleGui S(this, eIsCreatingFromPrefs);
PopulateOrExchange(S);
@ -130,8 +159,13 @@ void ExportMP2Options::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2, wxCENTER);
{
S.TieChoice(_("Bit Rate:"), wxT("/FileFormats/MP2Bitrate"),
160, mBitRateNames, mBitRateLabels);
S.TieNumberAsChoice(
_("Bit Rate:"),
wxT("/FileFormats/MP2Bitrate"),
160,
BitRateNames,
&BitRateValues
);
}
S.EndMultiColumn();
}
@ -202,7 +236,7 @@ ExportMP2::ExportMP2()
AddExtension(wxT("mp2"),0);
SetMaxChannels(2,0);
SetCanMetaData(true,0);
SetDescription(_("MP2 Files"),0);
SetDescription(XO("MP2 Files"),0);
}
ProgressResult ExportMP2::Export(AudacityProject *project,

View File

@ -105,118 +105,111 @@
// ExportMP3Options
//----------------------------------------------------------------------------
#define CHANNEL_JOINT 0
#define CHANNEL_STEREO 1
#define CHANNEL_MONO 2
enum MP3ChannelMode : unsigned {
CHANNEL_JOINT = 0,
CHANNEL_STEREO = 1,
CHANNEL_MONO = 2,
};
#define QUALITY_0 0
#define QUALITY_1 1
#define QUALITY_2 2
#define QUALITY_3 3
#define QUALITY_4 4
#define QUALITY_5 5
#define QUALITY_6 6
#define QUALITY_7 7
#define QUALITY_8 8
#define QUALITY_9 9
enum : int {
QUALITY_2 = 2,
#define ROUTINE_FAST 0
#define ROUTINE_STANDARD 1
ROUTINE_FAST = 0,
ROUTINE_STANDARD = 1,
#define PRESET_INSANE 0
#define PRESET_EXTREME 1
#define PRESET_STANDARD 2
#define PRESET_MEDIUM 3
PRESET_INSANE = 0,
PRESET_EXTREME = 1,
PRESET_STANDARD = 2,
PRESET_MEDIUM = 3,
};
// Note: The label field is what will be written to preferences and carries
// no numerical significance. It is simply a means to look up a value
// in a table.
//
// The entries should be listed in order you want them to appear in the
// choice dropdown based on the name field.
typedef struct
{
wxString name;
int label;
} CHOICES;
static CHOICES fixRates[] =
{
static const wxArrayStringEx fixRateNames {
/* i18n-hint: kbps is the bitrate of the MP3 file, kilobits per second*/
{wxT(""), 320},
{wxT(""), 256},
{wxT(""), 224},
{wxT(""), 192},
{wxT(""), 160},
{wxT(""), 144},
{wxT(""), 128},
{wxT(""), 112},
{wxT(""), 96},
{wxT(""), 80},
{wxT(""), 64},
{wxT(""), 56},
{wxT(""), 48},
{wxT(""), 40},
{wxT(""), 32},
{wxT(""), 24},
{wxT(""), 16},
{wxT(""), 8}
XO("320 kbps"),
XO("256 kbps"),
XO("224 kbps"),
XO("192 kbps"),
XO("160 kbps"),
XO("144 kbps"),
XO("128 kbps"),
XO("112 kbps"),
XO("96 kbps"),
XO("80 kbps"),
XO("64 kbps"),
XO("56 kbps"),
XO("48 kbps"),
XO("40 kbps"),
XO("32 kbps"),
XO("24 kbps"),
XO("16 kbps"),
XO("8 kbps"),
};
static CHOICES varRates[] =
{
{wxT(""), QUALITY_0},
{wxT(""), QUALITY_1},
{wxT(""), QUALITY_2},
{wxT(""), QUALITY_3},
{wxT(""), QUALITY_4},
{wxT(""), QUALITY_5},
{wxT(""), QUALITY_6},
{wxT(""), QUALITY_7},
{wxT(""), QUALITY_8},
{wxT(""), QUALITY_9}
static const std::vector<int> fixRateValues {
320,
256,
224,
192,
160,
144,
128,
112,
96,
80,
64,
56,
48,
40,
32,
24,
16,
8,
};
static const wxChar *const varRatesNumbers[] = {
wxT("220-260"),
wxT("200-250"),
wxT("170-210"),
wxT("155-195"),
wxT("145-185"),
wxT("110-150"),
wxT("95-135"),
wxT("80-120"),
wxT("65-105"),
wxT("45-85")
};
static_assert( WXSIZEOF(varRates) == WXSIZEOF(varRatesNumbers),
"size mismatch" );
static CHOICES varModes[] =
{
{wxT(""), ROUTINE_FAST },
{wxT(""), ROUTINE_STANDARD}
static const wxArrayStringEx varRateNames {
XO("220-260 kbps (Best Quality)"),
XO("200-250 kbps"),
XO("170-210 kbps"),
XO("155-195 kbps"),
XO("145-185 kbps"),
XO("110-150 kbps"),
XO("95-135 kbps"),
XO("80-120 kbps"),
XO("65-105 kbps"),
XO("45-85 kbps (Smaller files)"),
};
static CHOICES setRates[] =
{
{wxT(""), PRESET_INSANE },
{wxT(""), PRESET_EXTREME },
{wxT(""), PRESET_STANDARD},
{wxT(""), PRESET_MEDIUM }
static const wxArrayStringEx varModeNames {
XO("Fast"),
XO("Standard"),
};
static CHOICES sampRates[] =
{
{wxT(""), 8000 },
{wxT(""), 11025 },
{wxT(""), 12000 },
{wxT(""), 16000 },
{wxT(""), 22050 },
{wxT(""), 24000 },
{wxT(""), 32000 },
{wxT(""), 44100 },
{wxT(""), 48000 }
static const wxArrayStringEx setRateNames {
/* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
XO("Insane, 320 kbps"),
XO("Extreme, 220-260 kbps"),
XO("Standard, 170-210 kbps"),
XO("Medium, 145-185 kbps"),
};
static const wxArrayStringEx setRateNamesShort {
/* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
XO("Insane"),
XO("Extreme"),
XO("Standard"),
XO("Medium"),
};
static const std::vector< int > sampRates {
8000,
11025,
12000,
16000,
22050,
24000,
32000,
44100,
48000,
};
#define ID_SET 7000
@ -226,33 +219,6 @@ static CHOICES sampRates[] =
#define ID_QUALITY 7004
#define ID_MONO 7005
static void InitMP3_Statics()
{
for (size_t i=0; i < WXSIZEOF(fixRates); i++)
fixRates[i].name = wxString::Format(_("%d kbps"), fixRates[i].label);
varRates[0].name = wxString::Format(
_("%s kbps (Best Quality)"), varRatesNumbers[0] );
for (size_t i = 1; i < WXSIZEOF(varRates) - 1; i++)
varRates[i].name = wxString::Format( _("%s kbps"), varRatesNumbers[i] );
varRates[9].name = wxString::Format(
_("%s kbps (Smaller files)"), varRatesNumbers[9] );
varModes[0].name = _("Fast");
varModes[1].name = _("Standard");
/* i18n-hint: Slightly humorous - as in use an insane precision with MP3.*/
setRates[0].name = _("Insane, 320 kbps");
setRates[1].name = _("Extreme, 220-260 kbps");
setRates[2].name = _("Standard, 170-210 kbps");
setRates[3].name = _("Medium, 145-185 kbps");
for (size_t i=0; i < WXSIZEOF(sampRates); i++)
sampRates[i].name = wxString::Format( wxT("%d"), sampRates[i].label );
}
class ExportMP3Options final : public wxPanelWrapper
{
public:
@ -271,10 +237,7 @@ public:
void OnQuality(wxCommandEvent& evt);
void OnMono(wxCommandEvent& evt);
void LoadNames(CHOICES *choices, int count);
wxArrayString GetNames(CHOICES *choices, int count);
std::vector<int> GetLabels(CHOICES *choices, int count);
int FindIndex(CHOICES *choices, int cnt, int needle, int def);
void LoadNames(const wxArrayStringEx &choices);
private:
@ -310,8 +273,6 @@ END_EVENT_TABLE()
ExportMP3Options::ExportMP3Options(wxWindow *parent, int WXUNUSED(format))
: wxPanelWrapper(parent, wxID_ANY)
{
InitMP3_Statics();
mSetRate = gPrefs->Read(wxT("/FileFormats/MP3SetRate"), PRESET_STANDARD);
mVbrRate = gPrefs->Read(wxT("/FileFormats/MP3VbrRate"), QUALITY_2);
mAbrRate = gPrefs->Read(wxT("/FileFormats/MP3AbrRate"), 192);
@ -328,6 +289,38 @@ ExportMP3Options::~ExportMP3Options()
TransferDataFromWindow();
}
EnumSetting< MP3RateMode > MP3RateModeSetting{
wxT("/FileFormats/MP3RateModeChoice"),
{
{ wxT("SET"), XO("Preset") },
{ wxT("VBR"), XO("Variable") },
{ wxT("ABR"), XO("Average") },
{ wxT("CBR"), XO("Constant") },
},
0, // MODE_SET
// for migrating old preferences:
{
MODE_SET, MODE_VBR, MODE_ABR, MODE_CBR
},
wxT("/FileFormats/MP3RateMode"),
};
static EnumSetting< MP3ChannelMode > MP3ChannelModeSetting{
wxT("/FileFormats/MP3ChannelModeChoice"),
{
EnumValueSymbol{ wxT("JOINT"), XO("Joint Stereo") },
EnumValueSymbol{ wxT("STEREO"), XO("Stereo") },
},
0, // CHANNEL_JOINT
// for migrating old preferences:
{
CHANNEL_JOINT, CHANNEL_STEREO,
},
wxT("/FileFormats/MP3ChannelMode"),
};
///
///
void ExportMP3Options::PopulateOrExchange(ShuttleGui & S)
@ -344,59 +337,59 @@ void ExportMP3Options::PopulateOrExchange(ShuttleGui & S)
S.AddPrompt(_("Bit Rate Mode:"));
S.StartHorizontalLay();
{
S.StartRadioButtonGroup(wxT("/FileFormats/MP3RateMode"), MODE_SET);
S.StartRadioButtonGroup(MP3RateModeSetting);
{
mSET = S.Id(ID_SET).TieRadioButton(_("Preset"), MODE_SET);
mVBR = S.Id(ID_VBR).TieRadioButton(_("Variable"), MODE_VBR);
mABR = S.Id(ID_ABR).TieRadioButton(_("Average"), MODE_ABR);
mCBR = S.Id(ID_CBR).TieRadioButton(_("Constant"), MODE_CBR);
mSET = S.Id(ID_SET).TieRadioButton();
mVBR = S.Id(ID_VBR).TieRadioButton();
mABR = S.Id(ID_ABR).TieRadioButton();
mCBR = S.Id(ID_CBR).TieRadioButton();
}
S.EndRadioButtonGroup();
}
S.EndHorizontalLay();
CHOICES *choices;
int cnt;
const wxArrayStringEx *choices = nullptr;
const std::vector< int > *codes = nullptr;
bool enable;
int defrate;
if (mSET->GetValue()) {
choices = setRates;
cnt = WXSIZEOF(setRates);
choices = &setRateNames;
enable = true;
defrate = mSetRate;
}
else if (mVBR->GetValue()) {
choices = varRates;
cnt = WXSIZEOF(varRates);
choices = &varRateNames;
enable = true;
defrate = mVbrRate;
}
else if (mABR->GetValue()) {
choices = fixRates;
cnt = WXSIZEOF(fixRates);
choices = &fixRateNames;
codes = &fixRateValues;
enable = false;
defrate = mAbrRate;
}
else {
mCBR->SetValue(true);
choices = fixRates;
cnt = WXSIZEOF(fixRates);
choices = &fixRateNames;
codes = &fixRateValues;
enable = false;
defrate = mCbrRate;
}
mRate = S.Id(ID_QUALITY).TieChoice(_("Quality"),
wxT("/FileFormats/MP3Bitrate"),
defrate,
GetNames(choices, cnt),
GetLabels(choices, cnt));
mMode = S.TieChoice(_("Variable Speed:"),
wxT("/FileFormats/MP3VarMode"),
ROUTINE_FAST,
GetNames(varModes, WXSIZEOF(varModes)),
GetLabels(varModes, WXSIZEOF(varModes)));
mRate = S.Id(ID_QUALITY).TieNumberAsChoice(
_("Quality"),
wxT("/FileFormats/MP3Bitrate"),
defrate,
*choices,
codes
);
mMode = S.TieNumberAsChoice(
_("Variable Speed:"),
wxT("/FileFormats/MP3VarMode"),
ROUTINE_FAST,
varModeNames );
mMode->Enable(enable);
S.AddPrompt(_("Channel Mode:"));
@ -405,10 +398,10 @@ void ExportMP3Options::PopulateOrExchange(ShuttleGui & S)
bool mono = false;
gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &mono, 0);
S.StartRadioButtonGroup(wxT("/FileFormats/MP3ChannelMode"), CHANNEL_JOINT);
S.StartRadioButtonGroup(MP3ChannelModeSetting);
{
mJoint = S.TieRadioButton(_("Joint Stereo"), CHANNEL_JOINT);
mStereo = S.TieRadioButton(_("Stereo"), CHANNEL_STEREO);
mJoint = S.TieRadioButton();
mStereo = S.TieRadioButton();
mJoint->Enable(!mono);
mStereo->Enable(!mono);
}
@ -448,13 +441,28 @@ bool ExportMP3Options::TransferDataFromWindow()
return true;
}
namespace {
int ValidateValue( int nValues, int value, int defaultValue )
{
return (value >= 0 && value < nValues) ? value : defaultValue;
}
int ValidateValue( const std::vector<int> &values, int value, int defaultValue )
{
auto start = values.begin(), finish = values.end(),
iter = std::find( start, finish, value );
return ( iter != finish ) ? value : defaultValue;
}
}
///
///
void ExportMP3Options::OnSET(wxCommandEvent& WXUNUSED(event))
{
LoadNames(setRates, WXSIZEOF(setRates));
LoadNames(setRateNames);
mRate->SetSelection(FindIndex(setRates, WXSIZEOF(setRates), mSetRate, 2));
mRate->SetSelection(ValidateValue(setRateNames.size(), mSetRate, 2));
mRate->Refresh();
mMode->Enable(true);
}
@ -463,9 +471,9 @@ void ExportMP3Options::OnSET(wxCommandEvent& WXUNUSED(event))
///
void ExportMP3Options::OnVBR(wxCommandEvent& WXUNUSED(event))
{
LoadNames(varRates, WXSIZEOF(varRates));
LoadNames(varRateNames);
mRate->SetSelection(FindIndex(varRates, WXSIZEOF(varRates), mVbrRate, 2));
mRate->SetSelection(ValidateValue(varRateNames.size(), mVbrRate, 2));
mRate->Refresh();
mMode->Enable(true);
}
@ -474,9 +482,9 @@ void ExportMP3Options::OnVBR(wxCommandEvent& WXUNUSED(event))
///
void ExportMP3Options::OnABR(wxCommandEvent& WXUNUSED(event))
{
LoadNames(fixRates, WXSIZEOF(fixRates));
LoadNames(fixRateNames);
mRate->SetSelection(FindIndex(fixRates, WXSIZEOF(fixRates), mAbrRate, 10));
mRate->SetSelection(ValidateValue(fixRateValues, mAbrRate, 10));
mRate->Refresh();
mMode->Enable(false);
}
@ -485,9 +493,9 @@ void ExportMP3Options::OnABR(wxCommandEvent& WXUNUSED(event))
///
void ExportMP3Options::OnCBR(wxCommandEvent& WXUNUSED(event))
{
LoadNames(fixRates, WXSIZEOF(fixRates));
LoadNames(fixRateNames);
mRate->SetSelection(FindIndex(fixRates, WXSIZEOF(fixRates), mCbrRate, 10));
mRate->SetSelection(ValidateValue(fixRateValues, mCbrRate, 10));
mRate->Refresh();
mMode->Enable(false);
}
@ -497,16 +505,16 @@ void ExportMP3Options::OnQuality(wxCommandEvent& WXUNUSED(event))
int sel = mRate->GetSelection();
if (mSET->GetValue()) {
mSetRate = setRates[sel].label;
mSetRate = sel;
}
else if (mVBR->GetValue()) {
mVbrRate = varRates[sel].label;
mVbrRate = sel;
}
else if (mABR->GetValue()) {
mAbrRate = fixRates[sel].label;
mAbrRate = fixRateValues[ sel ];
}
else {
mCbrRate = fixRates[sel].label;
mCbrRate = fixRateValues[ sel ];
}
}
@ -521,47 +529,11 @@ void ExportMP3Options::OnMono(wxCommandEvent& /*evt*/)
gPrefs->Flush();
}
void ExportMP3Options::LoadNames(CHOICES *choices, int count)
void ExportMP3Options::LoadNames(const wxArrayStringEx &names)
{
mRate->Clear();
for (int i = 0; i < count; i++)
{
mRate->Append(choices[i].name);
}
}
wxArrayString ExportMP3Options::GetNames(CHOICES *choices, int count)
{
wxArrayString names;
for (int i = 0; i < count; i++) {
names.push_back(choices[i].name);
}
return names;
}
std::vector<int> ExportMP3Options::GetLabels(CHOICES *choices, int count)
{
std::vector<int> labels;
for (int i = 0; i < count; i++) {
labels.push_back(choices[i].label);
}
return labels;
}
int ExportMP3Options::FindIndex(CHOICES *choices, int cnt, int needle, int def)
{
for (int i = 0; i < cnt; i++) {
if (choices[i].label == needle) {
return i;
}
}
return def;
for (const auto &name : names)
mRate->Append( GetCustomTranslation( name ) );
}
//----------------------------------------------------------------------------
@ -1696,8 +1668,6 @@ public:
private:
int FindValue(CHOICES *choices, int cnt, int needle, int def);
wxString FindName(CHOICES *choices, int cnt, int needle);
int AskResample(int bitrate, int rate, int lowrate, int highrate);
unsigned long AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
#ifdef USE_LIBID3TAG
@ -1709,13 +1679,12 @@ private:
ExportMP3::ExportMP3()
: ExportPlugin()
{
InitMP3_Statics();
AddFormat();
SetFormat(wxT("MP3"),0);
AddExtension(wxT("mp3"),0);
SetMaxChannels(2,0);
SetCanMetaData(true,0);
SetDescription(_("MP3 Files"),0);
SetDescription(XO("MP3 Files"),0);
}
bool ExportMP3::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(format))
@ -1793,32 +1762,30 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
int lowrate = 8000;
int bitrate = 0;
int brate;
int rmode;
int vmode;
int cmode;
bool forceMono;
gPrefs->Read(wxT("/FileFormats/MP3Bitrate"), &brate, 128);
gPrefs->Read(wxT("/FileFormats/MP3RateMode"), &rmode, MODE_CBR);
auto rmode = MP3RateModeSetting.ReadEnumWithDefault( MODE_CBR );
gPrefs->Read(wxT("/FileFormats/MP3VarMode"), &vmode, ROUTINE_FAST);
gPrefs->Read(wxT("/FileFormats/MP3ChannelMode"), &cmode, CHANNEL_STEREO);
auto cmode = MP3ChannelModeSetting.ReadEnumWithDefault( CHANNEL_STEREO );
gPrefs->Read(wxT("/FileFormats/MP3ForceMono"), &forceMono, 0);
// Set the bitrate/quality and mode
if (rmode == MODE_SET) {
int q = FindValue(setRates, WXSIZEOF(setRates), brate, PRESET_STANDARD);
int r = FindValue(varModes, WXSIZEOF(varModes), vmode, ROUTINE_FAST);
brate = ValidateValue(setRateNames.size(), brate, PRESET_STANDARD);
int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
exporter.SetMode(MODE_SET);
exporter.SetQuality(q, r);
exporter.SetQuality(brate, r);
}
else if (rmode == MODE_VBR) {
int q = FindValue(varRates, WXSIZEOF(varRates), brate, QUALITY_2);
int r = FindValue(varModes, WXSIZEOF(varModes), vmode, ROUTINE_FAST);
brate = ValidateValue( varRateNames.size(), brate, QUALITY_2 );
int r = ValidateValue( varModeNames.size(), vmode, ROUTINE_FAST );
exporter.SetMode(MODE_VBR);
exporter.SetQuality(q, r);
exporter.SetQuality(brate, r);
}
else if (rmode == MODE_ABR) {
bitrate = FindValue(fixRates, WXSIZEOF(fixRates), brate, 128);
bitrate = brate = ValidateValue(fixRateValues, brate, 128);
exporter.SetMode(MODE_ABR);
exporter.SetBitrate(bitrate);
@ -1830,7 +1797,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
}
}
else {
bitrate = FindValue(fixRates, WXSIZEOF(fixRates), brate, 128);
bitrate = brate = ValidateValue(fixRateValues, brate, 128);
exporter.SetMode(MODE_CBR);
exporter.SetBitrate(bitrate);
@ -1843,7 +1810,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
}
// Verify sample rate
if (FindName(sampRates, WXSIZEOF(sampRates), rate).empty() ||
if (!make_iterator_range( sampRates ).contains( rate ) ||
(rate < lowrate) || (rate > highrate)) {
rate = AskResample(bitrate, rate, lowrate, highrate);
if (rate == 0) {
@ -1915,13 +1882,13 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
title.Printf(selectionOnly ?
_("Exporting selected audio with %s preset") :
_("Exporting the audio with %s preset"),
FindName(setRates, WXSIZEOF(setRates), brate));
setRateNamesShort[brate]);
}
else if (rmode == MODE_VBR) {
title.Printf(selectionOnly ?
_("Exporting selected audio with VBR quality %s") :
_("Exporting the audio with VBR quality %s"),
FindName(varRates, WXSIZEOF(varRates), brate));
varRateNames[brate]);
}
else {
title.Printf(selectionOnly ?
@ -2029,28 +1996,6 @@ wxWindow *ExportMP3::OptionsCreate(wxWindow *parent, int format)
return safenew ExportMP3Options(parent, format);
}
int ExportMP3::FindValue(CHOICES *choices, int cnt, int needle, int def)
{
for (int i = 0; i < cnt; i++) {
if (choices[i].label == needle) {
return needle;
}
}
return def;
}
wxString ExportMP3::FindName(CHOICES *choices, int cnt, int needle)
{
for (int i = 0; i < cnt; i++) {
if (choices[i].label == needle) {
return choices[i].name.BeforeFirst(wxT(','));
}
}
return wxT("");
}
int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
{
wxDialogWrapper d(nullptr, wxID_ANY, wxString(_("Invalid sample rate")));
@ -2080,12 +2025,12 @@ int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
wxArrayStringEx choices;
int selected = -1;
for (size_t i = 0; i < WXSIZEOF(sampRates); i++) {
int label = sampRates[i].label;
for (size_t ii = 0, nn = sampRates.size(); ii < nn; ++ii) {
int label = sampRates[ii];
if (label >= lowrate && label <= highrate) {
choices.push_back(sampRates[i].name);
choices.push_back( wxString::Format( "%d", label ) );
if (label <= rate) {
selected = i;
selected = ii;
}
}
}

View File

@ -15,10 +15,15 @@
#include "../MemoryX.h"
#define MODE_SET 0
#define MODE_VBR 1
#define MODE_ABR 2
#define MODE_CBR 3
enum MP3RateMode : unsigned {
MODE_SET = 0,
MODE_VBR,
MODE_ABR,
MODE_CBR,
};
template< typename Enum > class EnumSetting;
extern EnumSetting< MP3RateMode > MP3RateModeSetting;
#if defined(__WXMSW__) || defined(__WXMAC__)
#define MP3_EXPORT_BUILT_IN 1

View File

@ -234,7 +234,7 @@ void ExportMultiple::PopulateOrExchange(ShuttleGui& S)
++i;
for (int j = 0; j < pPlugin->GetFormatCount(); j++)
{
formats.push_back(mPlugins[i]->GetDescription(j));
formats.push_back(mPlugins[i]->GetUntranslatedDescription(j));
if (mPlugins[i]->GetFormat(j) == defaultFormat) {
mPluginIndex = i;
mSubFormatIndex = j;
@ -273,11 +273,13 @@ void ExportMultiple::PopulateOrExchange(ShuttleGui& S)
S.Id(CreateID).AddButton(_("Create"));
mFormat = S.Id(FormatID)
.TieChoice(_("Format:"),
wxT("/Export/MultipleFormat"),
formats[mFilterIndex],
formats,
formats);
.TieChoice( _("Format:"),
{
wxT("/Export/MultipleFormat"),
{ ByColumns, formats, formats },
mFilterIndex
}
);
S.AddVariableText( {}, false);
S.AddVariableText( {}, false);
@ -353,16 +355,21 @@ void ExportMultiple::PopulateOrExchange(ShuttleGui& S)
S.StartStatic(_("Name files:"), 1);
{
S.SetBorder(2);
S.StartRadioButtonGroup(wxT("/Export/TrackNameWithOrWithoutNumbers"), wxT("labelTrack"));
S.StartRadioButtonGroup({
wxT("/Export/TrackNameWithOrWithoutNumbers"),
{
{ wxT("labelTrack"), XO("Using Label/Track Name") },
{ wxT("numberBefore"), XO("Numbering before Label/Track Name") },
{ wxT("numberAfter"), XO("Numbering after File name prefix") },
},
0 // labelTrack
});
{
mByName = S.Id(ByNameID)
.TieRadioButton(_("Using Label/Track Name"), wxT("labelTrack"));
mByName = S.Id(ByNameID).TieRadioButton();
mByNumberAndName = S.Id(ByNameAndNumberID)
.TieRadioButton(_("Numbering before Label/Track Name"), wxT("numberBefore"));
mByNumberAndName = S.Id(ByNameAndNumberID).TieRadioButton();
mByNumber = S.Id(ByNumberID)
.TieRadioButton(_("Numbering after File name prefix"), wxT("numberAfter"));
mByNumber = S.Id(ByNumberID).TieRadioButton();
}
S.EndRadioButtonGroup();

View File

@ -157,7 +157,7 @@ ExportOGG::ExportOGG()
AddExtension(wxT("ogg"),0);
SetMaxChannels(255,0);
SetCanMetaData(true,0);
SetDescription(_("Ogg Vorbis Files"),0);
SetDescription(XO("Ogg Vorbis Files"),0);
}
ProgressResult ExportOGG::Export(AudacityProject *project,

View File

@ -53,7 +53,7 @@ struct
{
int format;
const wxChar *name;
const wxChar *desc;
const wxChar *desc; // untranslated
}
static const kFormats[] =
{
@ -374,7 +374,7 @@ ExportPCM::ExportPCM()
SetFormat(kFormats[i].name, format);
SetCanMetaData(true, format);
SetDescription(wxGetTranslation(kFormats[i].desc), format);
SetDescription(kFormats[i].desc, format);
AddExtension(ext, format);
SetMaxChannels(si.channels - 1, format);
}
@ -383,7 +383,7 @@ ExportPCM::ExportPCM()
format = AddFormat() - 1; // store the index = 1 less than the count
SetFormat(wxT("LIBSNDFILE"), format);
SetCanMetaData(true, format);
SetDescription(_("Other uncompressed files"), format);
SetDescription(XO("Other uncompressed files"), format);
auto allext = sf_get_all_extensions();
wxString wavext = sf_header_extension(SF_FORMAT_WAV); // get WAV ext.
#if defined(wxMSW)

View File

@ -236,7 +236,7 @@ auto PCMImportFileHandle::GetFileUncompressedBytes() -> ByteCount
static wxString AskCopyOrEdit()
{
wxString oldCopyPref = gPrefs->Read(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy"));
auto oldCopyPref = FileFormatsCopyOrEditSetting.Read();
bool firstTimeAsk = gPrefs->Read(wxT("/Warnings/CopyOrEditUncompressedDataFirstAsk"), true)?true:false;
bool oldAskPref = gPrefs->Read(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), true)?true:false;
@ -245,7 +245,7 @@ static wxString AskCopyOrEdit()
// This effectively does a one-time change to the preferences.
if (firstTimeAsk) {
if (oldCopyPref != wxT("copy")) {
gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy"));
FileFormatsCopyOrEditSetting.Write( wxT("copy") );
oldCopyPref = wxT("copy");
}
gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataFirstAsk"), (long) false);
@ -338,7 +338,7 @@ static wxString AskCopyOrEdit()
// if the preference changed, save it.
if (newCopyPref != oldCopyPref) {
gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), newCopyPref);
FileFormatsCopyOrEditSetting.Write( newCopyPref );
gPrefs->Flush();
}
oldCopyPref = newCopyPref;

View File

@ -18,6 +18,7 @@
#include "../effects/Contrast.h"
#include "../effects/EffectManager.h"
#include "../effects/RealtimeEffectManager.h"
#include "../prefs/EffectsPrefs.h"
// private helper classes and functions
namespace {
@ -195,7 +196,7 @@ void AddEffectMenuItems(
{
size_t pluginCnt = plugs.size();
wxString groupBy = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("sortby:name"));
auto groupBy = EffectsGroupBy.Read();
bool grouped = false;
if (groupBy.StartsWith(wxT("groupby")))
@ -382,7 +383,7 @@ MenuTable::BaseItemPtrs PopulateEffectsMenu(
plug = pm.GetNextPluginForEffectType(type);
}
wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("sortby:name"));
wxString groupby = EffectsGroupBy.Read();
using Comparator = bool(*)(const PluginDescriptor*, const PluginDescriptor*);
Comparator comp1, comp2;

View File

@ -133,11 +133,12 @@ void DevicePrefs::PopulateOrExchange(ShuttleGui & S)
S.StartMultiColumn(2);
{
S.Id(HostID);
mHost = S.TieChoice(_("&Host:"),
wxT("/AudioIO/Host"),
wxT(""),
mHostNames,
mHostLabels);
mHost = S.TieChoice( _("&Host:"),
{
wxT("/AudioIO/Host"),
{ ByColumns, mHostNames, mHostLabels }
}
);
S.AddPrompt(_("Using:"));
S.AddFixedText(wxString(wxSafeConvertMB2WX(Pa_GetVersionText())));

View File

@ -66,6 +66,28 @@ void EffectsPrefs::Populate()
// ----------------------- End of main section --------------
}
ChoiceSetting EffectsGroupBy{
wxT("/Effects/GroupBy"),
{
ByColumns,
{
XO("Sorted by Effect Name") ,
XO("Sorted by Publisher and Effect Name") ,
XO("Sorted by Type and Effect Name") ,
XO("Grouped by Publisher") ,
XO("Grouped by Type") ,
},
{
wxT("sortby:name") ,
wxT("sortby:publisher:name") ,
wxT("sortby:type:name") ,
wxT("groupby:publisher") ,
wxT("groupby:type") ,
}
},
0 // "sortby:name"
};
namespace {
// Rather than hard-code an exhaustive list of effect families in this file,
@ -177,27 +199,7 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
{
S.StartMultiColumn(2);
{
wxArrayStringEx visualgroups{
_("Sorted by Effect Name") ,
_("Sorted by Publisher and Effect Name") ,
_("Sorted by Type and Effect Name") ,
_("Grouped by Publisher") ,
_("Grouped by Type") ,
};
wxArrayStringEx prefsgroups{
wxT("sortby:name") ,
wxT("sortby:publisher:name") ,
wxT("sortby:type:name") ,
wxT("groupby:publisher") ,
wxT("groupby:type") ,
};
wxChoice *c = S.TieChoice(_("S&ort or Group:"),
wxT("/Effects/GroupBy"),
wxT("sortby:name"),
visualgroups,
prefsgroups);
wxChoice *c = S.TieChoice( _("S&ort or Group:"), EffectsGroupBy);
if( c ) c->SetMinSize(c->GetBestSize());
S.TieNumericTextBox(_("&Maximum effects per group (0 to disable):"),

View File

@ -17,6 +17,7 @@
#include "PrefsPanel.h"
class ChoiceSetting;
class ShuttleGui;
#define EFFECTS_PREFS_PLUGIN_SYMBOL ComponentInterfaceSymbol{ XO("Effects") }
@ -39,4 +40,7 @@ class EffectsPrefs final : public PrefsPanel
/// A PrefsPanel::Factory that creates one EffectsPrefs panel.
extern PrefsPanel::Factory EffectsPrefsFactory;
extern ChoiceSetting EffectsGroupBy;
#endif

View File

@ -67,37 +67,45 @@ wxString GUIPrefs::HelpPageName()
}
void GUIPrefs::GetRangeChoices(
wxArrayStringEx *pChoices, wxArrayStringEx *pCodes)
wxArrayStringEx *pChoicesUntranslated,
wxArrayStringEx *pChoicesTranslated,
wxArrayStringEx *pCodes,
int *pDefaultRangeIndex
)
{
if (pCodes) {
auto &codes = *pCodes;
codes.clear();
codes.insert( codes.end(), {
wxT("36") ,
wxT("48") ,
wxT("60") ,
wxT("72") ,
wxT("84") ,
wxT("96") ,
wxT("120") ,
wxT("145") ,
} );
}
static const auto sCodes = {
wxT("36") ,
wxT("48") ,
wxT("60") ,
wxT("72") ,
wxT("84") ,
wxT("96") ,
wxT("120") ,
wxT("145") ,
};
if (pCodes)
*pCodes = sCodes;
if (pChoices) {
auto &choices = *pChoices;
choices.clear();
choices.insert( choices.end(), {
_("-36 dB (shallow range for high-amplitude editing)") ,
_("-48 dB (PCM range of 8 bit samples)") ,
_("-60 dB (PCM range of 10 bit samples)") ,
_("-72 dB (PCM range of 12 bit samples)") ,
_("-84 dB (PCM range of 14 bit samples)") ,
_("-96 dB (PCM range of 16 bit samples)") ,
_("-120 dB (approximate limit of human hearing)") ,
_("-145 dB (PCM range of 24 bit samples)") ,
} );
}
static const auto sChoices = {
XO("-36 dB (shallow range for high-amplitude editing)") ,
XO("-48 dB (PCM range of 8 bit samples)") ,
XO("-60 dB (PCM range of 10 bit samples)") ,
XO("-72 dB (PCM range of 12 bit samples)") ,
XO("-84 dB (PCM range of 14 bit samples)") ,
XO("-96 dB (PCM range of 16 bit samples)") ,
XO("-120 dB (approximate limit of human hearing)") ,
XO("-145 dB (PCM range of 24 bit samples)") ,
};
if (pChoicesUntranslated)
*pChoicesUntranslated = sChoices;
if (pChoicesTranslated)
*pChoicesTranslated =
transform_container<wxArrayStringEx>( sChoices, GetCustomTranslation );
if (pDefaultRangeIndex)
*pDefaultRangeIndex = 2; // 60 == ENV_DB_RANGE
}
void GUIPrefs::Populate()
@ -105,43 +113,7 @@ void GUIPrefs::Populate()
// First any pre-processing for constructing the GUI.
GetLanguages(mLangCodes, mLangNames);
mHtmlHelpCodes.clear();
auto values = {
wxT("Local") ,
wxT("FromInternet") ,
};
mHtmlHelpCodes.insert( mHtmlHelpCodes.end(), values );
mHtmlHelpChoices.clear();
auto values2 = {
_("Local") ,
_("From Internet") ,
};
mHtmlHelpChoices.insert( mHtmlHelpChoices.end(), values2 );
mThemeCodes.clear();
mThemeCodes.insert( mThemeCodes.end(), {
wxT("classic") ,
wxT("light") ,
wxT("dark") ,
wxT("high-contrast") ,
wxT("custom") ,
} );
mThemeChoices.clear();
mThemeChoices.insert( mThemeChoices.end(), {
/* i18n-hint: describing the "classic" or traditional appearance of older versions of Audacity */
_("Classic") ,
/* i18n-hint: Light meaning opposite of dark */
_("Light") ,
_("Dark") ,
/* i18n-hint: greater difference between foreground and background colors */
_("High Contrast") ,
/* i18n-hint: user defined */
_("Custom") ,
} );
GetRangeChoices(&mRangeChoices, &mRangeCodes);
GetRangeChoices(&mRangeChoices, nullptr, &mRangeCodes, &mDefaultRangeIndex);
#if 0
mLangCodes.insert( mLangCodes.end(), {
@ -165,6 +137,52 @@ void GUIPrefs::Populate()
// ----------------------- End of main section --------------
}
ChoiceSetting GUIManualLocation{
wxT("/GUI/Help"),
{
ByColumns,
{ XO("Local") , XO("From Internet") , },
{ wxT("Local") , wxT("FromInternet") , }
},
0 // "Local"
};
constexpr int defaultTheme =
#ifdef EXPERIMENTAL_DA
2 // "dark"
#else
1 // "light"
#endif
;
ChoiceSetting GUITheme{
wxT("/GUI/Theme"),
{
ByColumns,
{
/* i18n-hint: describing the "classic" or traditional
appearance of older versions of Audacity */
XO("Classic") ,
/* i18n-hint: Light meaning opposite of dark */
XO("Light") ,
XO("Dark") ,
/* i18n-hint: greater difference between foreground and
background colors */
XO("High Contrast") ,
/* i18n-hint: user defined */
XO("Custom") ,
},
{
wxT("classic") ,
wxT("light") ,
wxT("dark") ,
wxT("high-contrast") ,
wxT("custom") ,
}
},
defaultTheme
};
void GUIPrefs::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(2);
@ -175,36 +193,24 @@ void GUIPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartMultiColumn(2);
{
#ifdef EXPERIMENTAL_DA
const wxString defaultTheme = wxT("dark");
#else
const wxString defaultTheme = wxT("light");
#endif
const wxString defaultRange = wxString::Format(wxT("%d"), ENV_DB_RANGE);
S.TieChoice( _("&Language:"),
{
wxT("/Locale/Language"),
{ ByColumns, mLangNames, mLangCodes }
}
);
S.TieChoice(_("&Language:"),
wxT("/Locale/Language"),
wxT(""),
mLangNames,
mLangCodes);
S.TieChoice( _("Location of &Manual:"), GUIManualLocation);
S.TieChoice(_("Location of &Manual:"),
wxT("/GUI/Help"),
wxT("Local"),
mHtmlHelpChoices,
mHtmlHelpCodes);
S.TieChoice( _("Th&eme:"), GUITheme);
S.TieChoice(_("Th&eme:"),
wxT("/GUI/Theme"),
defaultTheme,
mThemeChoices,
mThemeCodes);
S.TieChoice(_("Meter dB &range:"),
ENV_DB_KEY,
defaultRange,
mRangeChoices,
mRangeCodes);
S.TieChoice( _("Meter dB &range:"),
{
ENV_DB_KEY,
{ ByColumns, mRangeChoices, mRangeCodes },
mDefaultRangeIndex
}
);
}
S.EndMultiColumn();
// S.AddSpace(10);
@ -269,7 +275,7 @@ bool GUIPrefs::Commit()
gPrefs->Flush();
}
// Reads preference /GUI/Theme
// Reads preference GUITheme
theTheme.LoadPreferredTheme();
ThemePrefs::ApplyUpdatedImages();

View File

@ -17,6 +17,7 @@
#include "PrefsPanel.h"
class ChoiceSetting;
class ShuttleGui;
class wxArrayStringEx;
@ -35,7 +36,11 @@ class GUIPrefs final : public PrefsPanel
void PopulateOrExchange(ShuttleGui & S) override;
static void GetRangeChoices(
wxArrayStringEx *pChoices, wxArrayStringEx *pCodes);
wxArrayStringEx *pChoicesUntranslated,
wxArrayStringEx *pChoicesTranslated,
wxArrayStringEx *pCodes,
int *pDefaultRangeIndex = nullptr
);
// If no input language given, defaults first to choice in preferences, then
// to system language.
@ -55,14 +60,9 @@ class GUIPrefs final : public PrefsPanel
wxArrayStringEx mLangCodes;
wxArrayStringEx mLangNames;
wxArrayStringEx mHtmlHelpCodes;
wxArrayStringEx mHtmlHelpChoices;
wxArrayStringEx mThemeCodes;
wxArrayStringEx mThemeChoices;
wxArrayStringEx mRangeCodes;
wxArrayStringEx mRangeChoices;
int mDefaultRangeIndex;
};
/// A PrefsPanel::Factory that creates one GUIPrefs panel.
@ -70,4 +70,9 @@ extern PrefsPanel::Factory GUIPrefsFactory;
int ShowClippingPrefsID();
extern ChoiceSetting
GUIManualLocation
, GUITheme
;
#endif

View File

@ -20,6 +20,7 @@
#include <wx/defs.h>
#include "../FileFormats.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
@ -60,6 +61,36 @@ void ImportExportPrefs::Populate()
// ----------------------- End of main section --------------
}
EnumSetting< bool > ImportExportPrefs::ExportDownMixSetting{
wxT("/FileFormats/ExportDownMixChoice"),
{
EnumValueSymbol{ wxT("MixDown"), XO("&Mix down to Stereo or Mono") },
EnumValueSymbol{ wxT("Custom"), XO("&Use Advanced Mixing Options") },
},
0, // true
// for migrating old preferences:
{
true, false,
},
wxT("/FileFormats/ExportDownMix"),
};
EnumSetting< bool > ImportExportPrefs::AllegroStyleSetting{
wxT("/FileFormats/AllegroStyleChoice"),
{
EnumValueSymbol{ wxT("Seconds"), XO("&Seconds") },
EnumValueSymbol{ wxT("Beats"), XO("&Beats") },
},
0, // true
// for migrating old preferences:
{
true, false,
},
wxT("/FileFormats/AllegroStyle"),
};
void ImportExportPrefs::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(2);
@ -68,12 +99,10 @@ void ImportExportPrefs::PopulateOrExchange(ShuttleGui & S)
#ifdef EXPERIMENTAL_OD_DATA
S.StartStatic(_("When importing audio files"));
{
S.StartRadioButtonGroup(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy"));
S.StartRadioButtonGroup(FileFormatsCopyOrEditSetting);
{
S.TieRadioButton(_("&Copy uncompressed files into the project (safer)"),
wxT("copy"));
S.TieRadioButton(_("&Read uncompressed files from original location (faster)"),
wxT("edit"));
S.TieRadioButton();
S.TieRadioButton();
}
S.EndRadioButtonGroup();
}
@ -81,12 +110,10 @@ void ImportExportPrefs::PopulateOrExchange(ShuttleGui & S)
#endif
S.StartStatic(_("When exporting tracks to an audio file"));
{
S.StartRadioButtonGroup(wxT("/FileFormats/ExportDownMix"), true);
S.StartRadioButtonGroup(ImportExportPrefs::ExportDownMixSetting);
{
S.TieRadioButton(_("&Mix down to Stereo or Mono"),
true);
S.TieRadioButton(_("&Use Advanced Mixing Options"),
false);
S.TieRadioButton();
S.TieRadioButton();
}
S.EndRadioButtonGroup();
@ -102,12 +129,10 @@ void ImportExportPrefs::PopulateOrExchange(ShuttleGui & S)
#ifdef USE_MIDI
S.StartStatic(_("Exported Allegro (.gro) files save time as:"));
{
S.StartRadioButtonGroup(wxT("/FileFormats/AllegroStyle"), true);
S.StartRadioButtonGroup(ImportExportPrefs::AllegroStyleSetting);
{
S.TieRadioButton(_("&Seconds"),
true);
S.TieRadioButton(_("&Beats"),
false);
S.TieRadioButton();
S.TieRadioButton();
}
S.EndRadioButtonGroup();
}

View File

@ -21,9 +21,14 @@ class ShuttleGui;
#define IMPORT_EXPORT_PREFS_PLUGIN_SYMBOL ComponentInterfaceSymbol{ XO("IMPORT EXPORT") }
template< typename Enum > class EnumSetting;
class ImportExportPrefs final : public PrefsPanel
{
public:
static EnumSetting< bool > ExportDownMixSetting;
static EnumSetting< bool > AllegroStyleSetting;
ImportExportPrefs(wxWindow * parent, wxWindowID winid);
~ImportExportPrefs();
ComponentInterfaceSymbol GetSymbol() override;
@ -39,4 +44,5 @@ class ImportExportPrefs final : public PrefsPanel
/// A PrefsPanel::Factory that creates one ImportExportPrefs panel.
extern PrefsPanel::Factory ImportExportPrefsFactory;
#endif

View File

@ -174,13 +174,21 @@ void KeyConfigPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartHorizontalLay(wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 0);
{
S.AddTitle(_("View by:"));
S.StartRadioButtonGroup(wxT("/Prefs/KeyConfig/ViewBy"), wxT("tree"));
S.StartRadioButtonGroup({
wxT("/Prefs/KeyConfig/ViewBy"),
{
{ wxT("tree"), XO("&Tree") },
{ wxT("name"), XO("&Name") },
{ wxT("key"), XO("&Key") },
},
0 // tree
});
{
mViewByTree = S.Id(ViewByTreeID).TieRadioButton(_("&Tree"), wxT("tree"));
mViewByTree = S.Id(ViewByTreeID).TieRadioButton();
if( mViewByTree ) mViewByTree->SetName(_("View by tree"));
mViewByName = S.Id(ViewByNameID).TieRadioButton(_("&Name"), wxT("name"));
mViewByName = S.Id(ViewByNameID).TieRadioButton();
if( mViewByName ) mViewByName->SetName(_("View by name"));
mViewByKey = S.Id(ViewByKeyID).TieRadioButton(_("&Key"), wxT("key"));
mViewByKey = S.Id(ViewByKeyID).TieRadioButton();
if( mViewByKey ) mViewByKey->SetName(_("View by key"));
#if wxUSE_ACCESSIBILITY
// so that name can be set on a standard control

View File

@ -138,11 +138,12 @@ void MidiIOPrefs::PopulateOrExchange( ShuttleGui & S ) {
{
S.Id(HostID);
/* i18n-hint: (noun) */
mHost = S.TieChoice(_("&Host:"),
wxT("/MidiIO/Host"),
wxT(""),
mHostNames,
mHostLabels);
mHost = S.TieChoice( _("&Host:"),
{
wxT("/MidiIO/Host"),
{ ByColumns, mHostNames, mHostLabels }
}
);
S.AddPrompt(_("Using: PortMidi"));
}

View File

@ -22,6 +22,7 @@ handling.
#include <wx/defs.h>
#include <wx/textctrl.h>
#include "../FileFormats.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
@ -73,14 +74,11 @@ void ProjectsPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartStatic(_("When saving a project that depends on other audio files"));
{
S.StartRadioButtonGroup(wxT("/FileFormats/SaveProjectWithDependencies"), wxT("ask"));
S.StartRadioButtonGroup(FileFormatsSaveWithDependenciesSetting);
{
S.TieRadioButton(_("&Copy all audio into project (safest)"),
wxT("copy"));
S.TieRadioButton(_("Do &not copy any audio"),
wxT("never"));
S.TieRadioButton(_("As&k"),
wxT("ask"));
S.TieRadioButton();
S.TieRadioButton();
S.TieRadioButton();
}
S.EndRadioButtonGroup();
}

View File

@ -32,26 +32,21 @@
//////////
static const EnumValueSymbol choicesFormat[] = {
{ wxT("Format16Bit"), XO("16-bit") },
{ wxT("Format24Bit"), XO("24-bit") },
{ wxT("Format32BitFloat"), XO("32-bit float") }
};
static const size_t nChoicesFormat = WXSIZEOF( choicesFormat );
static const int intChoicesFormat[] = {
int16Sample,
int24Sample,
floatSample
};
static_assert( nChoicesFormat == WXSIZEOF(intChoicesFormat), "size mismatch" );
static const size_t defaultChoiceFormat = 2; // floatSample
static EnumSetting formatSetting{
static EnumSetting< sampleFormat > formatSetting{
wxT("/SamplingRate/DefaultProjectSampleFormatChoice"),
choicesFormat, nChoicesFormat, defaultChoiceFormat,
intChoicesFormat,
{
{ wxT("Format16Bit"), XO("16-bit") },
{ wxT("Format24Bit"), XO("24-bit") },
{ wxT("Format32BitFloat"), XO("32-bit float") }
},
2, // floatSample
// for migrating old preferences:
{
int16Sample,
int24Sample,
floatSample
},
wxT("/SamplingRate/DefaultProjectSampleFormat"),
};
@ -132,7 +127,7 @@ void QualityPrefs::GetNamesAndLabels()
mSampleRateNames.push_back(wxString::Format(wxT("%i Hz"), iRate));
}
mSampleRateNames.push_back(_("Other..."));
mSampleRateNames.push_back(XO("Other..."));
// The label for the 'Other...' case can be any value at all.
mSampleRateLabels.push_back(44100); // If chosen, this value will be overwritten
@ -162,7 +157,7 @@ void QualityPrefs::PopulateOrExchange(ShuttleGui & S)
wxT("/SamplingRate/DefaultProjectSampleRate"),
AudioIOBase::GetOptimalSupportedSampleRate(),
mSampleRateNames,
mSampleRateLabels);
&mSampleRateLabels);
// Now do the edit box...
mOtherSampleRate = S.TieNumericTextBox( {},
@ -246,6 +241,6 @@ QualityPrefsFactory = [](wxWindow *parent, wxWindowID winid)
sampleFormat QualityPrefs::SampleFormatChoice()
{
return (sampleFormat)formatSetting.ReadInt();
return formatSetting.ReadEnum();
}

View File

@ -56,14 +56,6 @@ const wxChar *TracksBehaviorsPrefs::ScrollingPreferenceKey()
void TracksBehaviorsPrefs::Populate()
{
mSoloCodes.push_back(wxT("Simple"));
mSoloCodes.push_back(wxT("Multi"));
mSoloCodes.push_back(wxT("None"));
mSoloChoices.push_back(_("Simple"));
mSoloChoices.push_back(_("Multi-track"));
mSoloChoices.push_back(_("None"));
//------------------------- Main section --------------------
// Now construct the GUI itself.
ShuttleGui S(this, eIsCreatingFromPrefs);
@ -71,6 +63,16 @@ void TracksBehaviorsPrefs::Populate()
// ----------------------- End of main section --------------
}
ChoiceSetting TracksBehaviorsSolo{
wxT("/GUI/Solo"),
{
ByColumns,
{ XO("Simple"), XO("Multi-track"), XO("None") },
{ wxT("Simple"), wxT("Multi"), wxT("None") }
},
0, // "Simple"
};
void TracksBehaviorsPrefs::PopulateOrExchange(ShuttleGui & S)
{
S.SetBorder(2);
@ -113,11 +115,7 @@ void TracksBehaviorsPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartMultiColumn(2);
{
S.TieChoice(_("Solo &Button:"),
wxT("/GUI/Solo"),
wxT("Standard"),
mSoloChoices,
mSoloCodes);
S.TieChoice( _("Solo &Button:"), TracksBehaviorsSolo);
}
S.EndMultiColumn();
}

View File

@ -16,6 +16,7 @@
#include "PrefsPanel.h"
class ChoiceSetting;
class ShuttleGui;
class wxArrayStringEx;
@ -38,11 +39,11 @@ class TracksBehaviorsPrefs final : public PrefsPanel
private:
void Populate();
void PopulateOrExchange(ShuttleGui & S) override;
wxArrayStringEx mSoloCodes;
wxArrayStringEx mSoloChoices;
};
/// A PrefsPanel::Factory that creates one TracksBehaviorsPrefs panel.
extern PrefsPanel::Factory TracksBehaviorsPrefsFactory;
extern ChoiceSetting TracksBehaviorsSolo;
#endif

View File

@ -54,33 +54,21 @@ namespace {
//////////
static const EnumValueSymbol choicesView[] = {
{ XO("Waveform") },
{ wxT("WaveformDB"), XO("Waveform (dB)") },
{ XO("Spectrogram") }
};
static const int intChoicesView[] = {
(int)(WaveTrackViewConstants::Waveform),
(int)(WaveTrackViewConstants::obsoleteWaveformDBDisplay),
(int)(WaveTrackViewConstants::Spectrum)
};
static const size_t nChoicesView = WXSIZEOF(choicesView);
static_assert( nChoicesView == WXSIZEOF(intChoicesView), "size mismatch" );
static const size_t defaultChoiceView = 0;
class TracksViewModeSetting : public EnumSetting {
class TracksViewModeEnumSetting
: public EnumSetting< WaveTrackViewConstants::Display > {
public:
TracksViewModeSetting(
TracksViewModeEnumSetting(
const wxString &key,
const EnumValueSymbol symbols[], size_t nSymbols,
size_t defaultSymbol,
EnumValueSymbols symbols,
long defaultSymbol,
const int intValues[],
std::initializer_list< WaveTrackViewConstants::Display > intValues,
const wxString &oldKey
)
: EnumSetting{
key, symbols, nSymbols, defaultSymbol, intValues, oldKey }
key, std::move( symbols ), defaultSymbol,
std::move( intValues ), oldKey
}
{}
void Migrate( wxString &value ) override
@ -106,56 +94,61 @@ public:
// Now future-proof 2.1.1 against a recurrence of this sort of bug!
viewMode = WaveTrackViewConstants::ValidateWaveTrackDisplay(viewMode);
const_cast<TracksViewModeSetting*>(this)->WriteInt( viewMode );
const_cast<TracksViewModeEnumSetting*>(this)->WriteInt( viewMode );
gPrefs->Flush();
value = mSymbols[ FindInt(viewMode) ].Internal();
}
};
static TracksViewModeSetting viewModeSetting{
static TracksViewModeEnumSetting viewModeSetting{
wxT("/GUI/DefaultViewModeChoice"),
choicesView, nChoicesView, defaultChoiceView,
{
{ XO("Waveform") },
{ wxT("WaveformDB"), XO("Waveform (dB)") },
{ XO("Spectrogram") }
},
0, // Waveform
intChoicesView,
// for migrating old preferences:
{
WaveTrackViewConstants::Waveform,
WaveTrackViewConstants::obsoleteWaveformDBDisplay,
WaveTrackViewConstants::Spectrum
},
wxT("/GUI/DefaultViewModeNew")
};
WaveTrackViewConstants::Display TracksPrefs::ViewModeChoice()
{
return (WaveTrackViewConstants::Display) viewModeSetting.ReadInt();
return viewModeSetting.ReadEnum();
}
//////////
static const EnumValueSymbol choicesSampleDisplay[] = {
{ wxT("ConnectDots"), XO("Connect dots") },
{ wxT("StemPlot"), XO("Stem plot") }
};
static const size_t nChoicesSampleDisplay = WXSIZEOF( choicesSampleDisplay );
static const int intChoicesSampleDisplay[] = {
(int) WaveTrackViewConstants::LinearInterpolate,
(int) WaveTrackViewConstants::StemPlot
};
static_assert(
nChoicesSampleDisplay == WXSIZEOF(intChoicesSampleDisplay), "size mismatch" );
static const size_t defaultChoiceSampleDisplay = 1;
static EnumSetting sampleDisplaySetting{
static EnumSetting< WaveTrackViewConstants::SampleDisplay >
sampleDisplaySetting{
wxT("/GUI/SampleViewChoice"),
choicesSampleDisplay, nChoicesSampleDisplay, defaultChoiceSampleDisplay,
{
{ wxT("ConnectDots"), XO("Connect dots") },
{ wxT("StemPlot"), XO("Stem plot") }
},
1, // StemPlot
intChoicesSampleDisplay,
// for migrating old preferences:
{
WaveTrackViewConstants::LinearInterpolate,
WaveTrackViewConstants::StemPlot
},
wxT("/GUI/SampleView")
};
WaveTrackViewConstants::SampleDisplay TracksPrefs::SampleViewChoice()
{
return (WaveTrackViewConstants::SampleDisplay) sampleDisplaySetting.ReadInt();
return sampleDisplaySetting.ReadEnum();
}
//////////
static const EnumValueSymbol choicesZoom[] = {
static const std::initializer_list<EnumValueSymbol> choicesZoom{
{ wxT("FitToWidth"), XO("Fit to Width") },
{ wxT("ZoomToSelection"), XO("Zoom to Selection") },
{ wxT("ZoomDefault"), XO("Zoom Default") },
@ -172,8 +165,7 @@ static const EnumValueSymbol choicesZoom[] = {
{ wxT("FourPixelsPerSample"), XO("4 Pixels per Sample") },
{ wxT("MaxZoom"), XO("Max Zoom") },
};
static const size_t nChoicesZoom = WXSIZEOF( choicesZoom );
static const int intChoicesZoom[] = {
static auto enumChoicesZoom = {
WaveTrackViewConstants::kZoomToFit,
WaveTrackViewConstants::kZoomToSelection,
WaveTrackViewConstants::kZoomDefault,
@ -190,36 +182,35 @@ static const int intChoicesZoom[] = {
WaveTrackViewConstants::kZoom4To1,
WaveTrackViewConstants::kMaxZoom,
};
static_assert( nChoicesZoom == WXSIZEOF(intChoicesZoom), "size mismatch" );
static const size_t defaultChoiceZoom1 = 2; // kZoomDefault
static EnumSetting zoom1Setting{
static EnumSetting< WaveTrackViewConstants::ZoomPresets > zoom1Setting{
wxT("/GUI/ZoomPreset1Choice"),
choicesZoom, nChoicesZoom, defaultChoiceZoom1,
choicesZoom,
2, // kZoomDefault
intChoicesZoom,
// for migrating old preferences:
enumChoicesZoom,
wxT("/GUI/ZoomPreset1")
};
static const size_t defaultChoiceZoom2 = 13; // kZoom4To1
static EnumSetting zoom2Setting{
static EnumSetting< WaveTrackViewConstants::ZoomPresets > zoom2Setting{
wxT("/GUI/ZoomPreset2Choice"),
choicesZoom, nChoicesZoom, defaultChoiceZoom2,
choicesZoom,
13, // kZoom4To1
intChoicesZoom,
// for migrating old preferences:
enumChoicesZoom,
wxT("/GUI/ZoomPreset2")
};
WaveTrackViewConstants::ZoomPresets TracksPrefs::Zoom1Choice()
{
return (WaveTrackViewConstants::ZoomPresets) zoom1Setting.ReadInt();
return zoom1Setting.ReadEnum();
}
WaveTrackViewConstants::ZoomPresets TracksPrefs::Zoom2Choice()
{
return (WaveTrackViewConstants::ZoomPresets) zoom2Setting.ReadInt();
return zoom2Setting.ReadEnum();
}
//////////

View File

@ -79,7 +79,7 @@ enum {
void WaveformPrefs::Populate()
{
// Reuse the same choices and codes as for Interface prefs
GUIPrefs::GetRangeChoices(&mRangeChoices, &mRangeCodes);
GUIPrefs::GetRangeChoices(nullptr, &mRangeChoices, &mRangeCodes);
//------------------------- Main section --------------------
// Now construct the GUI itself.

View File

@ -111,7 +111,7 @@ void WaveformSettings::ConvertToEnumeratedDBRange()
{
// Assumes the codes are in ascending sequence.
wxArrayStringEx codes;
GUIPrefs::GetRangeChoices(NULL, &codes);
GUIPrefs::GetRangeChoices(nullptr, nullptr, &codes);
int ii = 0;
for (int nn = codes.size(); ii < nn; ++ii) {
long value = 0;
@ -125,7 +125,7 @@ void WaveformSettings::ConvertToEnumeratedDBRange()
void WaveformSettings::ConvertToActualDBRange()
{
wxArrayStringEx codes;
GUIPrefs::GetRangeChoices(NULL, &codes);
GUIPrefs::GetRangeChoices(nullptr, nullptr, &codes);
long value = 0;
codes[std::max(0, std::min((int)(codes.size()) - 1, dBRange))]
.ToLong(&value);

View File

@ -46,6 +46,7 @@
#include "../HelpText.h"
#include "../Prefs.h"
#include "../wxFileNameWrapper.h"
#include "../prefs/GUIPrefs.h"
#ifdef USE_ALPHA_MANUAL
const wxString HelpSystem::HelpHostname = wxT("alphamanual.audacityteam.org");
@ -248,8 +249,8 @@ void HelpSystem::ShowHelp(wxWindow *parent,
// these next lines are for legacy cfg files (pre 2.0) where we had different modes
if( (HelpMode == wxT("Standard")) || (HelpMode == wxT("InBrowser")) )
{
HelpMode = wxT("Local");
gPrefs->Write(wxT("/GUI/Help"), HelpMode);
HelpMode = GUIManualLocation.Default().Internal();
GUIManualLocation.Write(HelpMode);
gPrefs->Flush();
}
}