1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-26 17:38:10 +02:00

Dynamic registry of sub-views replaces exhaustive switches on type...

... Such switches were in the TCP context menu for wave tracks,
SetTrackVisualsCommand, Nyquist (choosing the string for 'view property of
*tracks*), and the Tracks preferences panel.

This will allow easier, non-intrusive addition of other kinds of track
visualizations.
This commit is contained in:
Paul Licameli 2020-01-18 20:33:19 -05:00
commit 30999ab134
16 changed files with 244 additions and 117 deletions

View File

@ -87,9 +87,10 @@ public:
const wxString &Internal() const { return mInternal; } const wxString &Internal() const { return mInternal; }
const TranslatableString &Msgid() const { return mMsgid; } const TranslatableString &Msgid() const { return mMsgid; }
const TranslatableString Stripped() const { return mMsgid.Stripped(); }
const wxString Translation() const { return mMsgid.Translation(); } const wxString Translation() const { return mMsgid.Translation(); }
const wxString StrippedTranslation() const const wxString StrippedTranslation() const
{ return mMsgid.Stripped().Translation(); } { return Stripped().Translation(); }
bool empty() const { return mInternal.empty(); } bool empty() const { return mInternal.empty(); }

View File

@ -467,6 +467,8 @@ public:
TranslatableString Stripped( unsigned options = MenuCodes ) const TranslatableString Stripped( unsigned options = MenuCodes ) const
{ return TranslatableString{ *this }.Strip( options ); } { return TranslatableString{ *this }.Strip( options ); }
wxString StrippedTranslation() const { return Stripped().Translation(); }
private: private:
static const Formatter NullContextFormatter; static const Formatter NullContextFormatter;

View File

@ -214,7 +214,7 @@ public:
EnumValueSymbols symbols, EnumValueSymbols symbols,
long defaultSymbol, long defaultSymbol,
std::initializer_list< Enum > values, // must have same size as symbols std::vector< Enum > values, // must have same size as symbols
const wxString &oldKey = {} const wxString &oldKey = {}
) )
: EnumSettingBase{ : EnumSettingBase{

View File

@ -402,7 +402,7 @@ wxChoice * ShuttleGuiBase::AddChoice( const TranslatableString &Prompt,
wxDefaultPosition, wxDefaultPosition,
wxDefaultSize, wxDefaultSize,
transform_container<wxArrayString>( transform_container<wxArrayString>(
choices, std::mem_fn( &TranslatableString::Translation ) ), choices, std::mem_fn( &TranslatableString::StrippedTranslation ) ),
GetStyle( 0 ) ); GetStyle( 0 ) );
pChoice->SetMinSize( { 180, -1 } );// Use -1 for 'default size' - Platform specific. pChoice->SetMinSize( { 180, -1 } );// Use -1 for 'default size' - Platform specific.
@ -2421,7 +2421,7 @@ void ShuttleGui::SetMinSize( wxWindow *window, const TranslatableStrings & items
{ {
SetMinSize( window, SetMinSize( window,
transform_container<wxArrayStringEx>( transform_container<wxArrayStringEx>(
items, std::mem_fn( &TranslatableString::Translation ) ) ); items, std::mem_fn( &TranslatableString::StrippedTranslation ) ) );
} }
void ShuttleGui::SetMinSize( wxWindow *window, const wxArrayStringEx & items ) void ShuttleGui::SetMinSize( wxWindow *window, const wxArrayStringEx & items )

View File

@ -248,20 +248,6 @@ static const EnumValueSymbol kColourStrings[nColours] =
}; };
enum kDisplayTypes
{
kWaveform,
kSpectrogram,
nDisplayTypes
};
static const EnumValueSymbol kDisplayTypeStrings[nDisplayTypes] =
{
// These are acceptable dual purpose internal/visible names
{ XO("Waveform") },
{ XO("Spectrogram") },
};
enum kScaleTypes enum kScaleTypes
{ {
kLinear, kLinear,
@ -292,10 +278,22 @@ static const EnumValueSymbol kZoomTypeStrings[nZoomTypes] =
{ XO("HalfWave") }, { XO("HalfWave") },
}; };
static EnumValueSymbols DiscoverSubViewTypes()
{
const auto &types = WaveTrackSubView::AllTypes();
return transform_container< EnumValueSymbols >(
types, std::mem_fn( &WaveTrackSubView::Type::name ) );
}
bool SetTrackVisualsCommand::DefineParams( ShuttleParams & S ){ bool SetTrackVisualsCommand::DefineParams( ShuttleParams & S ){
SetTrackBase::DefineParams( S ); SetTrackBase::DefineParams( S );
S.OptionalN( bHasHeight ).Define( mHeight, wxT("Height"), 120, 44, 2000 ); S.OptionalN( bHasHeight ).Define( mHeight, wxT("Height"), 120, 44, 2000 );
S.OptionalN( bHasDisplayType ).DefineEnum( mDisplayType, wxT("Display"), kWaveform, kDisplayTypeStrings, nDisplayTypes );
{
auto symbols = DiscoverSubViewTypes();
S.OptionalN( bHasDisplayType ).DefineEnum( mDisplayType, wxT("Display"), 0, symbols.data(), symbols.size() );
}
S.OptionalN( bHasScaleType ).DefineEnum( mScaleType, wxT("Scale"), kLinear, kScaleTypeStrings, nScaleTypes ); S.OptionalN( bHasScaleType ).DefineEnum( mScaleType, wxT("Scale"), kLinear, kScaleTypeStrings, nScaleTypes );
S.OptionalN( bHasColour ).DefineEnum( mColour, wxT("Color"), kColour0, kColourStrings, nColours ); S.OptionalN( bHasColour ).DefineEnum( mColour, wxT("Color"), kColour0, kColourStrings, nColours );
S.OptionalN( bHasVZoom ).DefineEnum( mVZoom, wxT("VZoom"), kReset, kZoomTypeStrings, nZoomTypes ); S.OptionalN( bHasVZoom ).DefineEnum( mVZoom, wxT("VZoom"), kReset, kZoomTypeStrings, nZoomTypes );
@ -318,8 +316,15 @@ void SetTrackVisualsCommand::PopulateOrExchange(ShuttleGui & S)
S.Optional( bHasHeight ).TieNumericTextBox( XO("Height:"), mHeight ); S.Optional( bHasHeight ).TieNumericTextBox( XO("Height:"), mHeight );
S.Optional( bHasColour ).TieChoice( XO("Color:"), mColour, S.Optional( bHasColour ).TieChoice( XO("Color:"), mColour,
Msgids( kColourStrings, nColours ) ); Msgids( kColourStrings, nColours ) );
S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType,
Msgids( kDisplayTypeStrings, nDisplayTypes ) ); {
auto symbols = DiscoverSubViewTypes();
auto typeNames = transform_container<TranslatableStrings>(
symbols, std::mem_fn( &EnumValueSymbol::Stripped ) );
S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType,
typeNames );
}
S.Optional( bHasScaleType ).TieChoice( XO("Scale:"), mScaleType, S.Optional( bHasScaleType ).TieChoice( XO("Scale:"), mScaleType,
Msgids( kScaleTypeStrings, nScaleTypes ) ); Msgids( kScaleTypeStrings, nScaleTypes ) );
S.Optional( bHasVZoom ).TieChoice( XO("VZoom:"), mVZoom, S.Optional( bHasVZoom ).TieChoice( XO("VZoom:"), mVZoom,
@ -355,10 +360,7 @@ bool SetTrackVisualsCommand::ApplyInner(const CommandContext & context, Track *
if( wt && bHasDisplayType ) if( wt && bHasDisplayType )
WaveTrackView::Get( *wt ).SetDisplay( WaveTrackView::Get( *wt ).SetDisplay(
(mDisplayType == kWaveform) ? WaveTrackSubView::AllTypes()[ mDisplayType ].id );
WaveTrackViewConstants::Waveform
: WaveTrackViewConstants::Spectrum
);
if( wt && bHasScaleType ) if( wt && bHasScaleType )
wt->GetIndependentWaveformSettings().scaleType = wt->GetIndependentWaveformSettings().scaleType =
(mScaleType==kLinear) ? (mScaleType==kLinear) ?

View File

@ -551,9 +551,10 @@ bool NyquistEffect::Init()
for ( auto t : for ( auto t :
TrackList::Get( *project ).Selected< const WaveTrack >() ) { TrackList::Get( *project ).Selected< const WaveTrack >() ) {
const auto displays = WaveTrackView::Get(*t).GetDisplays(); const auto displays = WaveTrackView::Get(*t).GetDisplays();
bool hasSpectral = bool hasSpectral = (displays.end() != std::find(
make_iterator_range( displays.begin(), displays.end()) displays.begin(), displays.end(),
.contains( WaveTrackViewConstants::Spectrum ); WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
) );
if ( !hasSpectral || if ( !hasSpectral ||
!(t->GetSpectrogramSettings().SpectralSelectionEnabled())) { !(t->GetSpectrogramSettings().SpectralSelectionEnabled())) {
bAllowSpectralEditing = false; bAllowSpectralEditing = false;
@ -1090,21 +1091,16 @@ bool NyquistEffect::ProcessOne()
wxString bitFormat; wxString bitFormat;
wxString spectralEditp; wxString spectralEditp;
using namespace WaveTrackViewConstants;
mCurTrack[0]->TypeSwitch( mCurTrack[0]->TypeSwitch(
[&](const WaveTrack *wt) { [&](const WaveTrack *wt) {
type = wxT("wave"); type = wxT("wave");
spectralEditp = mCurTrack[0]->GetSpectrogramSettings().SpectralSelectionEnabled()? wxT("T") : wxT("NIL"); spectralEditp = mCurTrack[0]->GetSpectrogramSettings().SpectralSelectionEnabled()? wxT("T") : wxT("NIL");
auto displays = WaveTrackView::Get( *wt ).GetDisplays(); auto displays = WaveTrackView::Get( *wt ).GetDisplays();
auto format = [&]( decltype(displays[0]) display ){ auto format = [&]( decltype(displays[0]) display ) {
switch ( display ) // Get the English name of the view type, without menu codes,
{ // as a string that Lisp can examine
case Waveform: return wxString::Format( wxT("\"%s\""),
return wxT("\"Waveform\""); display.name.Stripped().Debug() );
case Spectrum:
return wxT("\"Spectrogram\"");
default: return wxT("NIL");
}
}; };
if (displays.empty()) if (displays.empty())
view = wxT("NIL"); view = wxT("NIL");

View File

@ -36,8 +36,11 @@ void DoNextPeakFrequency(AudacityProject &project, bool up)
const WaveTrack *pTrack {}; const WaveTrack *pTrack {};
for ( auto wt : tracks.Selected< const WaveTrack >() ) { for ( auto wt : tracks.Selected< const WaveTrack >() ) {
const auto displays = WaveTrackView::Get( *wt ).GetDisplays(); const auto displays = WaveTrackView::Get( *wt ).GetDisplays();
if ( make_iterator_range( displays.begin(), displays.end() ) bool hasSpectrum = (displays.end() != std::find(
.contains( WaveTrackViewConstants::Spectrum) ) { displays.begin(), displays.end(),
WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
) );
if ( hasSpectrum ) {
pTrack = wt; pTrack = wt;
break; break;
} }

View File

@ -27,6 +27,7 @@
#include "../Prefs.h" #include "../Prefs.h"
#include "../ShuttleGui.h" #include "../ShuttleGui.h"
#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h"
int TracksPrefs::iPreferencePinned = -1; int TracksPrefs::iPreferencePinned = -1;
@ -81,8 +82,6 @@ namespace {
const auto key2 = wxT("/GUI/DefaultViewModeChoice"); const auto key2 = wxT("/GUI/DefaultViewModeChoice");
const auto key3 = wxT("/GUI/DefaultViewModeChoiceNew"); const auto key3 = wxT("/GUI/DefaultViewModeChoiceNew");
const EnumValueSymbol waveformSymbol{ XO("Waveform") };
const EnumValueSymbol spectrumSymbol{ XO("Spectrogram") };
const wxString obsoleteValue{ wxT("WaveformDB") }; const wxString obsoleteValue{ wxT("WaveformDB") };
}; };
@ -100,6 +99,9 @@ public:
// to avoid confusing version 2.1.0 if it reads the preference file afterwards. // to avoid confusing version 2.1.0 if it reads the preference file afterwards.
// Prefer the NEW preference key if it is present // Prefer the NEW preference key if it is present
static const EnumValueSymbol waveformSymbol{ XO("Waveform") };
static const EnumValueSymbol spectrumSymbol{ XO("Spectrogram") };
WaveTrackViewConstants::Display viewMode; WaveTrackViewConstants::Display viewMode;
int oldMode; int oldMode;
wxString newValue; wxString newValue;
@ -143,23 +145,26 @@ public:
} }
}; };
static TracksViewModeEnumSetting viewModeSetting{ static TracksViewModeEnumSetting viewModeSetting()
key3, {
{ // Do a delayed computation, so that registration of sub-view types completes
{ waveformSymbol }, // first
{ spectrumSymbol } const auto &types = WaveTrackSubView::AllTypes();
}, auto symbols = transform_container< EnumValueSymbols >(
0, // Waveform types, std::mem_fn( &WaveTrackSubView::Type::name ) );
auto ids = transform_container< std::vector< WaveTrackSubView::Display > >(
{ types, std::mem_fn( &WaveTrackSubView::Type::id ) );
WaveTrackViewConstants::Waveform, return {
WaveTrackViewConstants::Spectrum key3,
} symbols,
}; 0, // Waveform
ids
};
}
WaveTrackViewConstants::Display TracksPrefs::ViewModeChoice() WaveTrackViewConstants::Display TracksPrefs::ViewModeChoice()
{ {
return viewModeSetting.ReadEnum(); return viewModeSetting().ReadEnum();
} }
WaveformSettings::ScaleTypeValues TracksPrefs::WaveformScaleChoice() WaveformSettings::ScaleTypeValues TracksPrefs::WaveformScaleChoice()
@ -344,7 +349,7 @@ void TracksPrefs::PopulateOrExchange(ShuttleGui & S)
#endif #endif
S.TieChoice(XO("Default &view mode:"), S.TieChoice(XO("Default &view mode:"),
viewModeSetting ); viewModeSetting() );
S.TieChoice(XO("Default Waveform scale:"), S.TieChoice(XO("Default Waveform scale:"),
waveformScaleSetting ); waveformScaleSetting );

View File

@ -150,7 +150,7 @@ void WaveformSettings::NextHigherDBRange()
const TranslatableStrings &WaveformSettings::GetScaleNames() const TranslatableStrings &WaveformSettings::GetScaleNames()
{ {
static const TranslatableStrings result{ static const TranslatableStrings result{
// Keep in correspondence with enum WaveTrack::WaveTrackDisplay: // Keep in correspondence with ScaleTypeValues:
XO("Linear"), XO("Linear"),
XO("dB"), XO("dB"),
}; };

View File

@ -30,6 +30,13 @@ Paul Licameli split from WaveTrackView.cpp
#include <wx/dcmemory.h> #include <wx/dcmemory.h>
#include <wx/graphics.h> #include <wx/graphics.h>
static WaveTrackSubView::Type sType{
WaveTrackViewConstants::Spectrum,
{ wxT("Spectrogram"), XO("&Spectrogram") }
};
static WaveTrackSubView::RegisteredType reg{ sType };
SpectrumView::~SpectrumView() = default; SpectrumView::~SpectrumView() = default;
bool SpectrumView::IsSpectral() const bool SpectrumView::IsSpectral() const
@ -73,9 +80,9 @@ void SpectrumView::DoSetMinimized( bool minimized )
TrackView::DoSetMinimized( minimized ); TrackView::DoSetMinimized( minimized );
} }
WaveTrackViewConstants::Display SpectrumView::SubViewType() const auto SpectrumView::SubViewType() const -> const Type &
{ {
return WaveTrackViewConstants::Spectrum; return sType;
} }
std::shared_ptr<TrackVRulerControls> SpectrumView::DoGetVRulerControls() std::shared_ptr<TrackVRulerControls> SpectrumView::DoGetVRulerControls()

View File

@ -24,7 +24,7 @@ public:
using WaveTrackSubView::WaveTrackSubView; using WaveTrackSubView::WaveTrackSubView;
~SpectrumView() override; ~SpectrumView() override;
virtual WaveTrackViewConstants::Display SubViewType() const override; const Type &SubViewType() const override;
std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override; std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;

View File

@ -104,6 +104,8 @@ std::vector<UIHandlePtr> WaveTrackControls::HitTest
} }
enum { enum {
reserveDisplays = 100,
OnRate8ID = 30000, // <--- OnRate8ID = 30000, // <---
OnRate11ID, // | OnRate11ID, // |
OnRate16ID, // | OnRate16ID, // |
@ -123,8 +125,9 @@ enum {
OnFloatID, // <--- OnFloatID, // <---
OnMultiViewID, OnMultiViewID,
OnWaveformID,
OnSpectrumID, OnSetDisplayId, lastDisplayId = (OnSetDisplayId + reserveDisplays - 1),
OnSpectrogramSettingsID, OnSpectrogramSettingsID,
OnChannelLeftID, OnChannelLeftID,
@ -620,6 +623,16 @@ void WaveTrackMenuTable::InitUserData(void *pUserData)
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData); mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
} }
static WaveTrackSubView::Types AllTypes()
{
auto result = WaveTrackSubView::AllTypes();
if ( result.size() > reserveDisplays ) {
wxASSERT( false );
result.resize( reserveDisplays );
}
return result;
}
void WaveTrackMenuTable::InitMenu(Menu *pMenu) void WaveTrackMenuTable::InitMenu(Menu *pMenu)
{ {
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack); WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
@ -631,16 +644,40 @@ void WaveTrackMenuTable::InitMenu(Menu *pMenu)
if (multiView) if (multiView)
checkedIds.push_back( OnMultiViewID ); checkedIds.push_back( OnMultiViewID );
bool hasSpectrum = false;
int uniqueDisplay = 0; int uniqueDisplay = 0;
{
// Find the set of type ids of the shown displays, disregarding their
// top-to-bottom arrangement
auto displays = view.GetDisplays();
const auto end = displays.end();
auto iter = displays.begin();
std::sort( iter, end );
const auto displays = view.GetDisplays(); // Check the corresponding menu items, and decide which if any has
for ( auto display : displays ) { // the unique check
auto id = (display == WaveTrackViewConstants::Waveform) int displayId = OnSetDisplayId;
? OnWaveformID int nDisplays = 0;
: OnSpectrumID; for ( const auto &type : AllTypes() ) {
checkedIds.push_back( id ); if ( iter != end && iter->id == type.id ) {
if ( displays.size() == 1 ) checkedIds.push_back( displayId );
uniqueDisplay = id; uniqueDisplay = displayId;
++iter;
++nDisplays;
// Unfortunately this special knowledge of the Spectrum view type
// remains. In future, either let a registry system insert this
// menu item, or (better) move it to the context menu of the
// Spectrum vertical ruler.
// (But the latter won't be satisfactory without a means to
// open that other context menu with keystrokes only, and that
// would require some notion of a focused sub-view.)
hasSpectrum = ( type.id == WaveTrackViewConstants::Spectrum );
}
++displayId;
}
if ( nDisplays > 1 )
uniqueDisplay = 0;
} }
if ( multiView && uniqueDisplay ) if ( multiView && uniqueDisplay )
@ -652,9 +689,6 @@ void WaveTrackMenuTable::InitMenu(Menu *pMenu)
// We can't change them on the fly yet anyway. // We can't change them on the fly yet anyway.
auto gAudioIO = AudioIOBase::Get(); auto gAudioIO = AudioIOBase::Get();
const bool bAudioBusy = gAudioIO->IsBusy(); const bool bAudioBusy = gAudioIO->IsBusy();
bool hasSpectrum =
make_iterator_range( displays.begin(), displays.end() )
.contains( WaveTrackViewConstants::Spectrum );
pMenu->Enable(OnSpectrogramSettingsID, hasSpectrum && !bAudioBusy); pMenu->Enable(OnSpectrogramSettingsID, hasSpectrum && !bAudioBusy);
AudacityProject *const project = &mpData->project; AudacityProject *const project = &mpData->project;
@ -733,13 +767,14 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
if ( WaveTrackSubViews::slots() > 1 ) if ( WaveTrackSubViews::slots() > 1 )
POPUP_MENU_CHECK_ITEM(OnMultiViewID, XO("&Multi-view"), OnMultiView) POPUP_MENU_CHECK_ITEM(OnMultiViewID, XO("&Multi-view"), OnMultiView)
if ( view.GetMultiView() ) { int id = OnSetDisplayId;
POPUP_MENU_CHECK_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay) for ( const auto &type : AllTypes() ) {
POPUP_MENU_CHECK_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay) if ( view.GetMultiView() ) {
} POPUP_MENU_CHECK_ITEM(id++, type.name.Msgid(), OnSetDisplay)
else { }
POPUP_MENU_RADIO_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay) else {
POPUP_MENU_RADIO_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay) POPUP_MENU_RADIO_ITEM(id++, type.name.Msgid(), OnSetDisplay)
}
} }
POPUP_MENU_ITEM(OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings) POPUP_MENU_ITEM(OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings)
@ -761,9 +796,10 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
if ( pTrack ) { if ( pTrack ) {
const auto displays = view.GetDisplays(); const auto displays = view.GetDisplays();
bool hasWaveform = bool hasWaveform = (displays.end() != std::find(
make_iterator_range( displays.begin(), displays.end() ) displays.begin(), displays.end(),
.contains( WaveTrackViewConstants::Waveform ); WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} }
) );
if( hasWaveform ){ if( hasWaveform ){
POPUP_MENU_SEPARATOR() POPUP_MENU_SEPARATOR()
POPUP_MENU_SUB_MENU(OnWaveColorID, XO("&Wave Color"), WaveColorMenuTable) POPUP_MENU_SUB_MENU(OnWaveColorID, XO("&Wave Color"), WaveColorMenuTable)
@ -784,7 +820,7 @@ void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event)
bool multi = !view.GetMultiView(); bool multi = !view.GetMultiView();
const auto &displays = view.GetDisplays(); const auto &displays = view.GetDisplays();
const auto display = displays.empty() const auto display = displays.empty()
? WaveTrackViewConstants::Waveform : *displays.begin(); ? WaveTrackViewConstants::Waveform : displays.begin()->id;
for (const auto channel : TrackList::Channels(pTrack)) { for (const auto channel : TrackList::Channels(pTrack)) {
auto &channelView = WaveTrackView::Get( *channel ); auto &channelView = WaveTrackView::Get( *channel );
channelView.SetMultiView( multi ); channelView.SetMultiView( multi );
@ -799,24 +835,18 @@ void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event)
/// Set the Display mode based on the menu choice in the Track Menu. /// Set the Display mode based on the menu choice in the Track Menu.
void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event) void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
{ {
using namespace WaveTrackViewConstants;
int idInt = event.GetId(); int idInt = event.GetId();
wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID); wxASSERT(idInt >= OnSetDisplayId &&
idInt <= lastDisplayId);
const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack); const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
WaveTrackView::WaveTrackDisplay id; auto id = AllTypes()[ idInt - OnSetDisplayId ].id;
switch (idInt) {
default:
case OnWaveformID:
id = Waveform; break;
case OnSpectrumID:
id = Spectrum; break;
}
auto &view = WaveTrackView::Get( *pTrack ); auto &view = WaveTrackView::Get( *pTrack );
if ( view.GetMultiView() ) { if ( view.GetMultiView() ) {
for (auto channel : TrackList::Channels(pTrack)) { for (auto channel : TrackList::Channels(pTrack)) {
if ( !WaveTrackView::Get( *channel ).ToggleSubView( id ) ) { if ( !WaveTrackView::Get( *channel )
.ToggleSubView( WaveTrackView::Display{ id } ) ) {
// Trying to toggle off the last sub-view. It was refused. // Trying to toggle off the last sub-view. It was refused.
// Decide what to do here. Turn off multi-view instead? // Decide what to do here. Turn off multi-view instead?
// PRL: I don't agree that it makes sense // PRL: I don't agree that it makes sense
@ -827,12 +857,13 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
} }
else { else {
const auto displays = view.GetDisplays(); const auto displays = view.GetDisplays();
const bool wrongType = !(displays.size() == 1 && displays[0] == id); const bool wrongType =
!(displays.size() == 1 && displays[0].id == id);
if (wrongType) { if (wrongType) {
for (auto channel : TrackList::Channels(pTrack)) { for (auto channel : TrackList::Channels(pTrack)) {
channel->SetLastScaleType(); channel->SetLastScaleType();
WaveTrackView::Get( *channel ) WaveTrackView::Get( *channel )
.SetDisplay(WaveTrackView::WaveTrackDisplay(id)); .SetDisplay( WaveTrackView::Display{ id } );
} }
AudacityProject *const project = &mpData->project; AudacityProject *const project = &mpData->project;
@ -886,7 +917,7 @@ void WaveTrackMenuTable::OnSpectrogramSettings(wxCommandEvent &)
// factories.push_back(WaveformPrefsFactory( pTrack )); // factories.push_back(WaveformPrefsFactory( pTrack ));
factories.push_back(SpectrumPrefsFactory( pTrack )); factories.push_back(SpectrumPrefsFactory( pTrack ));
const int page = const int page =
// (pTrack->GetDisplay() == WaveTrack::Spectrum) ? 1 : // (pTrack->GetDisplay() == WaveTrackViewConstants::Spectrum) ? 1 :
0; 0;
auto title = XO("%s:").Format( pTrack->GetName() ); auto title = XO("%s:").Format( pTrack->GetName() );

View File

@ -40,6 +40,53 @@ Paul Licameli split from TrackPanel.cpp
#include "../../../ui/ButtonHandle.h" #include "../../../ui/ButtonHandle.h"
#include "../../../../TrackInfo.h" #include "../../../../TrackInfo.h"
namespace {
class Registry {
public:
using Type = WaveTrackSubView::Type;
using Types = std::vector< Type >;
void Append( Type type )
{
types.emplace_back( std::move( type ) );
sorted = false;
}
Types &Get()
{
if ( !sorted ) {
auto begin = types.begin(), end = types.end();
std::sort( begin, end );
// We don't want duplicate ids!
wxASSERT( end == std::adjacent_find( begin, end ) );
sorted = true;
}
return types;
}
private:
Types types;
bool sorted = false;
};
Registry &GetRegistry()
{
static Registry result;
return result;
}
}
WaveTrackSubView::RegisteredType::RegisteredType( Type type )
{
GetRegistry().Append( std::move( type ) );
}
// static
auto WaveTrackSubView::AllTypes() -> const Types &
{
return GetRegistry().Get();
}
namespace { namespace {
using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >; using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >;
@ -842,12 +889,13 @@ WaveTrackView::DoDetailedHitTest
return { false, results }; return { false, results };
} }
auto WaveTrackView::GetDisplays() const -> std::vector<WaveTrackDisplay> auto WaveTrackView::GetDisplays() const
-> std::vector< WaveTrackSubView::Type >
{ {
BuildSubViews(); BuildSubViews();
// Collect the display types of visible views and sort them by position // Collect the display types of visible views and sort them by position
using Pair = std::pair< int, WaveTrackDisplay >; using Pair = std::pair< int, WaveTrackSubView::Type >;
std::vector< Pair > pairs; std::vector< Pair > pairs;
size_t ii = 0; size_t ii = 0;
WaveTrackSubViews::ForEach( [&]( const WaveTrackSubView &subView ){ WaveTrackSubViews::ForEach( [&]( const WaveTrackSubView &subView ){
@ -857,24 +905,24 @@ auto WaveTrackView::GetDisplays() const -> std::vector<WaveTrackDisplay>
++ii; ++ii;
} ); } );
std::sort( pairs.begin(), pairs.end() ); std::sort( pairs.begin(), pairs.end() );
std::vector<WaveTrackDisplay> results; std::vector< WaveTrackSubView::Type > results;
for ( const auto &pair : pairs ) for ( const auto &pair : pairs )
results.push_back( pair.second ); results.push_back( pair.second );
return results; return results;
} }
void WaveTrackView::SetDisplay(WaveTrackDisplay display, bool exclusive) void WaveTrackView::SetDisplay(Display display, bool exclusive)
{ {
BuildSubViews(); BuildSubViews();
DoSetDisplay( display, exclusive ); DoSetDisplay( display, exclusive );
} }
bool WaveTrackView::ToggleSubView(WaveTrackDisplay display) bool WaveTrackView::ToggleSubView(Display display)
{ {
size_t ii = 0; size_t ii = 0;
size_t found = 0; size_t found = 0;
if ( WaveTrackSubViews::FindIf( [&]( const WaveTrackSubView &subView ) { if ( WaveTrackSubViews::FindIf( [&]( const WaveTrackSubView &subView ) {
if ( subView.SubViewType() == display ) { if ( subView.SubViewType().id == display ) {
found = ii; found = ii;
return true; return true;
} }
@ -927,7 +975,7 @@ bool WaveTrackView::ToggleSubView(WaveTrackDisplay display)
// If exclusive, make the chosen view take up all the height. Else, // If exclusive, make the chosen view take up all the height. Else,
// partition equally, putting the specified view on top. // partition equally, putting the specified view on top.
// Be sure the sequence in which the other views appear is determinate. // Be sure the sequence in which the other views appear is determinate.
void WaveTrackView::DoSetDisplay(WaveTrackDisplay display, bool exclusive) void WaveTrackView::DoSetDisplay(Display display, bool exclusive)
{ {
// Some generality here anticipating more than two views. // Some generality here anticipating more than two views.
// The order of sub-views in the array is not specified, so make it definite // The order of sub-views in the array is not specified, so make it definite
@ -935,7 +983,7 @@ void WaveTrackView::DoSetDisplay(WaveTrackDisplay display, bool exclusive)
size_t ii = 0; size_t ii = 0;
std::vector< std::pair< WaveTrackViewConstants::Display, size_t > > pairs; std::vector< std::pair< WaveTrackViewConstants::Display, size_t > > pairs;
WaveTrackSubViews::ForEach( [&pairs, &ii]( WaveTrackSubView &subView ){ WaveTrackSubViews::ForEach( [&pairs, &ii]( WaveTrackSubView &subView ){
pairs.push_back( { subView.SubViewType(), ii++ } ); pairs.push_back( { subView.SubViewType().id, ii++ } );
} ); } );
std::sort( pairs.begin(), pairs.end() ); std::sort( pairs.begin(), pairs.end() );

View File

@ -13,19 +13,44 @@ Paul Licameli split from class WaveTrack
#include "../../../ui/CommonTrackView.h" #include "../../../ui/CommonTrackView.h"
#include "../../../../ClientData.h" #include "../../../../ClientData.h"
#include "audacity/ComponentInterface.h"
namespace WaveTrackViewConstants{ enum Display : int; } namespace WaveTrackViewConstants{ enum Display : int; }
class CutlineHandle; class CutlineHandle;
class TranslatableString;
class WaveTrack; class WaveTrack;
class WaveTrackView; class WaveTrackView;
class WaveTrackSubView : public CommonTrackView class WaveTrackSubView : public CommonTrackView
{ {
public: public:
using Display = WaveTrackViewConstants::Display;
struct Type {
// Identifies the type session-wide, and determines relative position in
// menus listing all types
Display id;
// The translation is suitable for the track control panel drop-down,
// and it may contain a menu accelerator
EnumValueSymbol name;
bool operator < ( const Type &other ) const { return id < other.id; }
bool operator == ( const Type &other ) const { return id == other.id; }
};
using Types = std::vector< Type >;
// Typically a file scope statically constructed object
struct RegisteredType {
RegisteredType( Type type );
};
// Discover all registered types
static const Types &AllTypes();
explicit explicit
WaveTrackSubView( WaveTrackView &waveTrackView ); WaveTrackSubView( WaveTrackView &waveTrackView );
virtual WaveTrackViewConstants::Display SubViewType() const = 0; virtual const Type &SubViewType() const = 0;
std::pair< std::pair<
bool, // if true, hit-testing is finished bool, // if true, hit-testing is finished
@ -67,6 +92,8 @@ class WaveTrackView final
WaveTrackView &operator=( const WaveTrackView& ) = delete; WaveTrackView &operator=( const WaveTrackView& ) = delete;
public: public:
using Display = WaveTrackViewConstants::Display;
static WaveTrackView &Get( WaveTrack &track ); static WaveTrackView &Get( WaveTrack &track );
static const WaveTrackView &Get( const WaveTrack &track ); static const WaveTrackView &Get( const WaveTrack &track );
@ -91,10 +118,8 @@ public:
const std::shared_ptr<WaveTrack> &wt, const std::shared_ptr<WaveTrack> &wt,
CommonTrackView &view); CommonTrackView &view);
using WaveTrackDisplay = WaveTrackViewConstants::Display; std::vector< WaveTrackSubView::Type > GetDisplays() const;
void SetDisplay(Display display, bool exclusive = true);
std::vector<WaveTrackDisplay> GetDisplays() const;
void SetDisplay(WaveTrackDisplay display, bool exclusive = true);
const WaveTrackSubViewPlacements &SavePlacements() const const WaveTrackSubViewPlacements &SavePlacements() const
{ return mPlacements; } { return mPlacements; }
@ -103,7 +128,7 @@ public:
// Return true if successful. Fails if you try to toggle off the only // Return true if successful. Fails if you try to toggle off the only
// sub-view. // sub-view.
bool ToggleSubView( WaveTrackDisplay id ); bool ToggleSubView( Display id );
// Get all the sub-views, in a sequence that is unspecified but in // Get all the sub-views, in a sequence that is unspecified but in
// correspondence with the result of SavePlacements // correspondence with the result of SavePlacements
@ -117,7 +142,7 @@ public:
private: private:
void BuildSubViews() const; void BuildSubViews() const;
void DoSetDisplay(WaveTrackDisplay display, bool exclusive = true); void DoSetDisplay(Display display, bool exclusive = true);
// TrackPanelDrawable implementation // TrackPanelDrawable implementation
void Draw( void Draw(

View File

@ -36,6 +36,13 @@ Paul Licameli split from WaveTrackView.cpp
#include <wx/graphics.h> #include <wx/graphics.h>
#include <wx/dc.h> #include <wx/dc.h>
static WaveTrackSubView::Type sType{
WaveTrackViewConstants::Waveform,
{ wxT("Waveform"), XO("Wa&veform") }
};
static WaveTrackSubView::RegisteredType reg{ sType };
WaveformView::~WaveformView() = default; WaveformView::~WaveformView() = default;
std::vector<UIHandlePtr> WaveformView::DetailedHitTest( std::vector<UIHandlePtr> WaveformView::DetailedHitTest(
@ -119,9 +126,9 @@ void WaveformView::DoSetMinimized( bool minimized )
TrackView::DoSetMinimized( minimized ); TrackView::DoSetMinimized( minimized );
} }
WaveTrackViewConstants::Display WaveformView::SubViewType() const auto WaveformView::SubViewType() const -> const Type &
{ {
return WaveTrackViewConstants::Waveform; return sType;
} }
std::shared_ptr<TrackVRulerControls> WaveformView::DoGetVRulerControls() std::shared_ptr<TrackVRulerControls> WaveformView::DoGetVRulerControls()

View File

@ -26,7 +26,7 @@ public:
using WaveTrackSubView::WaveTrackSubView; using WaveTrackSubView::WaveTrackSubView;
~WaveformView() override; ~WaveformView() override;
virtual WaveTrackViewConstants::Display SubViewType() const override; const Type &SubViewType() const override;
std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override; std::shared_ptr<TrackVRulerControls> DoGetVRulerControls() override;