diff --git a/include/audacity/ComponentInterface.h b/include/audacity/ComponentInterface.h index 6a5fd0eb3..149ecf8e2 100644 --- a/include/audacity/ComponentInterface.h +++ b/include/audacity/ComponentInterface.h @@ -87,9 +87,10 @@ public: const wxString &Internal() const { return mInternal; } const TranslatableString &Msgid() const { return mMsgid; } + const TranslatableString Stripped() const { return mMsgid.Stripped(); } const wxString Translation() const { return mMsgid.Translation(); } const wxString StrippedTranslation() const - { return mMsgid.Stripped().Translation(); } + { return Stripped().Translation(); } bool empty() const { return mInternal.empty(); } diff --git a/include/audacity/Types.h b/include/audacity/Types.h index 144773533..e21551458 100644 --- a/include/audacity/Types.h +++ b/include/audacity/Types.h @@ -467,6 +467,8 @@ public: TranslatableString Stripped( unsigned options = MenuCodes ) const { return TranslatableString{ *this }.Strip( options ); } + wxString StrippedTranslation() const { return Stripped().Translation(); } + private: static const Formatter NullContextFormatter; diff --git a/src/Prefs.h b/src/Prefs.h index 3086d3dc2..723bd400e 100644 --- a/src/Prefs.h +++ b/src/Prefs.h @@ -214,7 +214,7 @@ public: EnumValueSymbols symbols, 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 = {} ) : EnumSettingBase{ diff --git a/src/ShuttleGui.cpp b/src/ShuttleGui.cpp index 7d57375e6..f86de3500 100644 --- a/src/ShuttleGui.cpp +++ b/src/ShuttleGui.cpp @@ -402,7 +402,7 @@ wxChoice * ShuttleGuiBase::AddChoice( const TranslatableString &Prompt, wxDefaultPosition, wxDefaultSize, transform_container( - choices, std::mem_fn( &TranslatableString::Translation ) ), + choices, std::mem_fn( &TranslatableString::StrippedTranslation ) ), GetStyle( 0 ) ); 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, transform_container( - items, std::mem_fn( &TranslatableString::Translation ) ) ); + items, std::mem_fn( &TranslatableString::StrippedTranslation ) ) ); } void ShuttleGui::SetMinSize( wxWindow *window, const wxArrayStringEx & items ) diff --git a/src/commands/SetTrackInfoCommand.cpp b/src/commands/SetTrackInfoCommand.cpp index 3f2b2b973..61aed48ea 100644 --- a/src/commands/SetTrackInfoCommand.cpp +++ b/src/commands/SetTrackInfoCommand.cpp @@ -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 { kLinear, @@ -292,10 +278,22 @@ static const EnumValueSymbol kZoomTypeStrings[nZoomTypes] = { 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 ){ SetTrackBase::DefineParams( S ); 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( bHasColour ).DefineEnum( mColour, wxT("Color"), kColour0, kColourStrings, nColours ); 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( bHasColour ).TieChoice( XO("Color:"), mColour, Msgids( kColourStrings, nColours ) ); - S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType, - Msgids( kDisplayTypeStrings, nDisplayTypes ) ); + + { + auto symbols = DiscoverSubViewTypes(); + auto typeNames = transform_container( + symbols, std::mem_fn( &EnumValueSymbol::Stripped ) ); + S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType, + typeNames ); + } + S.Optional( bHasScaleType ).TieChoice( XO("Scale:"), mScaleType, Msgids( kScaleTypeStrings, nScaleTypes ) ); S.Optional( bHasVZoom ).TieChoice( XO("VZoom:"), mVZoom, @@ -355,10 +360,7 @@ bool SetTrackVisualsCommand::ApplyInner(const CommandContext & context, Track * if( wt && bHasDisplayType ) WaveTrackView::Get( *wt ).SetDisplay( - (mDisplayType == kWaveform) ? - WaveTrackViewConstants::Waveform - : WaveTrackViewConstants::Spectrum - ); + WaveTrackSubView::AllTypes()[ mDisplayType ].id ); if( wt && bHasScaleType ) wt->GetIndependentWaveformSettings().scaleType = (mScaleType==kLinear) ? diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index c76f1d0a4..cab019312 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -551,9 +551,10 @@ bool NyquistEffect::Init() for ( auto t : TrackList::Get( *project ).Selected< const WaveTrack >() ) { const auto displays = WaveTrackView::Get(*t).GetDisplays(); - bool hasSpectral = - make_iterator_range( displays.begin(), displays.end()) - .contains( WaveTrackViewConstants::Spectrum ); + bool hasSpectral = (displays.end() != std::find( + displays.begin(), displays.end(), + WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} } + ) ); if ( !hasSpectral || !(t->GetSpectrogramSettings().SpectralSelectionEnabled())) { bAllowSpectralEditing = false; @@ -1090,21 +1091,16 @@ bool NyquistEffect::ProcessOne() wxString bitFormat; wxString spectralEditp; - using namespace WaveTrackViewConstants; mCurTrack[0]->TypeSwitch( [&](const WaveTrack *wt) { type = wxT("wave"); spectralEditp = mCurTrack[0]->GetSpectrogramSettings().SpectralSelectionEnabled()? wxT("T") : wxT("NIL"); auto displays = WaveTrackView::Get( *wt ).GetDisplays(); - auto format = [&]( decltype(displays[0]) display ){ - switch ( display ) - { - case Waveform: - return wxT("\"Waveform\""); - case Spectrum: - return wxT("\"Spectrogram\""); - default: return wxT("NIL"); - } + auto format = [&]( decltype(displays[0]) display ) { + // Get the English name of the view type, without menu codes, + // as a string that Lisp can examine + return wxString::Format( wxT("\"%s\""), + display.name.Stripped().Debug() ); }; if (displays.empty()) view = wxT("NIL"); diff --git a/src/menus/SelectMenus.cpp b/src/menus/SelectMenus.cpp index da25e42bf..d60d642ee 100644 --- a/src/menus/SelectMenus.cpp +++ b/src/menus/SelectMenus.cpp @@ -36,8 +36,11 @@ void DoNextPeakFrequency(AudacityProject &project, bool up) const WaveTrack *pTrack {}; for ( auto wt : tracks.Selected< const WaveTrack >() ) { const auto displays = WaveTrackView::Get( *wt ).GetDisplays(); - if ( make_iterator_range( displays.begin(), displays.end() ) - .contains( WaveTrackViewConstants::Spectrum) ) { + bool hasSpectrum = (displays.end() != std::find( + displays.begin(), displays.end(), + WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} } + ) ); + if ( hasSpectrum ) { pTrack = wt; break; } diff --git a/src/prefs/TracksPrefs.cpp b/src/prefs/TracksPrefs.cpp index b3a7ebe4c..2875a5014 100644 --- a/src/prefs/TracksPrefs.cpp +++ b/src/prefs/TracksPrefs.cpp @@ -27,6 +27,7 @@ #include "../Prefs.h" #include "../ShuttleGui.h" +#include "../tracks/playabletrack/wavetrack/ui/WaveTrackView.h" int TracksPrefs::iPreferencePinned = -1; @@ -81,8 +82,6 @@ namespace { const auto key2 = wxT("/GUI/DefaultViewModeChoice"); const auto key3 = wxT("/GUI/DefaultViewModeChoiceNew"); - const EnumValueSymbol waveformSymbol{ XO("Waveform") }; - const EnumValueSymbol spectrumSymbol{ XO("Spectrogram") }; const wxString obsoleteValue{ wxT("WaveformDB") }; }; @@ -100,6 +99,9 @@ public: // to avoid confusing version 2.1.0 if it reads the preference file afterwards. // Prefer the NEW preference key if it is present + static const EnumValueSymbol waveformSymbol{ XO("Waveform") }; + static const EnumValueSymbol spectrumSymbol{ XO("Spectrogram") }; + WaveTrackViewConstants::Display viewMode; int oldMode; wxString newValue; @@ -143,23 +145,26 @@ public: } }; -static TracksViewModeEnumSetting viewModeSetting{ - key3, - { - { waveformSymbol }, - { spectrumSymbol } - }, - 0, // Waveform - - { - WaveTrackViewConstants::Waveform, - WaveTrackViewConstants::Spectrum - } -}; +static TracksViewModeEnumSetting viewModeSetting() +{ + // Do a delayed computation, so that registration of sub-view types completes + // first + const auto &types = WaveTrackSubView::AllTypes(); + auto symbols = transform_container< EnumValueSymbols >( + types, std::mem_fn( &WaveTrackSubView::Type::name ) ); + auto ids = transform_container< std::vector< WaveTrackSubView::Display > >( + types, std::mem_fn( &WaveTrackSubView::Type::id ) ); + return { + key3, + symbols, + 0, // Waveform + ids + }; +} WaveTrackViewConstants::Display TracksPrefs::ViewModeChoice() { - return viewModeSetting.ReadEnum(); + return viewModeSetting().ReadEnum(); } WaveformSettings::ScaleTypeValues TracksPrefs::WaveformScaleChoice() @@ -344,7 +349,7 @@ void TracksPrefs::PopulateOrExchange(ShuttleGui & S) #endif S.TieChoice(XO("Default &view mode:"), - viewModeSetting ); + viewModeSetting() ); S.TieChoice(XO("Default Waveform scale:"), waveformScaleSetting ); diff --git a/src/prefs/WaveformSettings.cpp b/src/prefs/WaveformSettings.cpp index 923ac0fca..71d461bd6 100644 --- a/src/prefs/WaveformSettings.cpp +++ b/src/prefs/WaveformSettings.cpp @@ -150,7 +150,7 @@ void WaveformSettings::NextHigherDBRange() const TranslatableStrings &WaveformSettings::GetScaleNames() { static const TranslatableStrings result{ - // Keep in correspondence with enum WaveTrack::WaveTrackDisplay: + // Keep in correspondence with ScaleTypeValues: XO("Linear"), XO("dB"), }; diff --git a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp index 5ec43a594..1a6922f09 100644 --- a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp @@ -30,6 +30,13 @@ Paul Licameli split from WaveTrackView.cpp #include #include +static WaveTrackSubView::Type sType{ + WaveTrackViewConstants::Spectrum, + { wxT("Spectrogram"), XO("&Spectrogram") } +}; + +static WaveTrackSubView::RegisteredType reg{ sType }; + SpectrumView::~SpectrumView() = default; bool SpectrumView::IsSpectral() const @@ -73,9 +80,9 @@ void SpectrumView::DoSetMinimized( bool minimized ) TrackView::DoSetMinimized( minimized ); } -WaveTrackViewConstants::Display SpectrumView::SubViewType() const +auto SpectrumView::SubViewType() const -> const Type & { - return WaveTrackViewConstants::Spectrum; + return sType; } std::shared_ptr SpectrumView::DoGetVRulerControls() diff --git a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h index 5fc9c49d1..787370e2e 100644 --- a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h +++ b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h @@ -24,7 +24,7 @@ public: using WaveTrackSubView::WaveTrackSubView; ~SpectrumView() override; - virtual WaveTrackViewConstants::Display SubViewType() const override; + const Type &SubViewType() const override; std::shared_ptr DoGetVRulerControls() override; diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp index 4997e4605..e2b9681a6 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackControls.cpp @@ -104,6 +104,8 @@ std::vector WaveTrackControls::HitTest } enum { + reserveDisplays = 100, + OnRate8ID = 30000, // <--- OnRate11ID, // | OnRate16ID, // | @@ -123,8 +125,9 @@ enum { OnFloatID, // <--- OnMultiViewID, - OnWaveformID, - OnSpectrumID, + + OnSetDisplayId, lastDisplayId = (OnSetDisplayId + reserveDisplays - 1), + OnSpectrogramSettingsID, OnChannelLeftID, @@ -620,6 +623,16 @@ void WaveTrackMenuTable::InitUserData(void *pUserData) mpData = static_cast(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) { WaveTrack *const pTrack = static_cast(mpData->pTrack); @@ -631,16 +644,40 @@ void WaveTrackMenuTable::InitMenu(Menu *pMenu) if (multiView) checkedIds.push_back( OnMultiViewID ); + bool hasSpectrum = false; 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(); - for ( auto display : displays ) { - auto id = (display == WaveTrackViewConstants::Waveform) - ? OnWaveformID - : OnSpectrumID; - checkedIds.push_back( id ); - if ( displays.size() == 1 ) - uniqueDisplay = id; + // Check the corresponding menu items, and decide which if any has + // the unique check + int displayId = OnSetDisplayId; + int nDisplays = 0; + for ( const auto &type : AllTypes() ) { + if ( iter != end && iter->id == type.id ) { + checkedIds.push_back( displayId ); + 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 ) @@ -652,9 +689,6 @@ void WaveTrackMenuTable::InitMenu(Menu *pMenu) // We can't change them on the fly yet anyway. auto gAudioIO = AudioIOBase::Get(); const bool bAudioBusy = gAudioIO->IsBusy(); - bool hasSpectrum = - make_iterator_range( displays.begin(), displays.end() ) - .contains( WaveTrackViewConstants::Spectrum ); pMenu->Enable(OnSpectrogramSettingsID, hasSpectrum && !bAudioBusy); AudacityProject *const project = &mpData->project; @@ -733,13 +767,14 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable) if ( WaveTrackSubViews::slots() > 1 ) POPUP_MENU_CHECK_ITEM(OnMultiViewID, XO("&Multi-view"), OnMultiView) - if ( view.GetMultiView() ) { - POPUP_MENU_CHECK_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay) - POPUP_MENU_CHECK_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay) - } - else { - POPUP_MENU_RADIO_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay) - POPUP_MENU_RADIO_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay) + int id = OnSetDisplayId; + for ( const auto &type : AllTypes() ) { + if ( view.GetMultiView() ) { + POPUP_MENU_CHECK_ITEM(id++, type.name.Msgid(), OnSetDisplay) + } + else { + POPUP_MENU_RADIO_ITEM(id++, type.name.Msgid(), OnSetDisplay) + } } POPUP_MENU_ITEM(OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings) @@ -761,9 +796,10 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable) if ( pTrack ) { const auto displays = view.GetDisplays(); - bool hasWaveform = - make_iterator_range( displays.begin(), displays.end() ) - .contains( WaveTrackViewConstants::Waveform ); + bool hasWaveform = (displays.end() != std::find( + displays.begin(), displays.end(), + WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} } + ) ); if( hasWaveform ){ POPUP_MENU_SEPARATOR() POPUP_MENU_SUB_MENU(OnWaveColorID, XO("&Wave Color"), WaveColorMenuTable) @@ -784,7 +820,7 @@ void WaveTrackMenuTable::OnMultiView(wxCommandEvent & event) bool multi = !view.GetMultiView(); const auto &displays = view.GetDisplays(); const auto display = displays.empty() - ? WaveTrackViewConstants::Waveform : *displays.begin(); + ? WaveTrackViewConstants::Waveform : displays.begin()->id; for (const auto channel : TrackList::Channels(pTrack)) { auto &channelView = WaveTrackView::Get( *channel ); 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. void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event) { - using namespace WaveTrackViewConstants; int idInt = event.GetId(); - wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID); + wxASSERT(idInt >= OnSetDisplayId && + idInt <= lastDisplayId); const auto pTrack = static_cast(mpData->pTrack); - WaveTrackView::WaveTrackDisplay id; - switch (idInt) { - default: - case OnWaveformID: - id = Waveform; break; - case OnSpectrumID: - id = Spectrum; break; - } + auto id = AllTypes()[ idInt - OnSetDisplayId ].id; auto &view = WaveTrackView::Get( *pTrack ); if ( view.GetMultiView() ) { 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. // Decide what to do here. Turn off multi-view instead? // PRL: I don't agree that it makes sense @@ -827,12 +857,13 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event) } else { 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) { for (auto channel : TrackList::Channels(pTrack)) { channel->SetLastScaleType(); WaveTrackView::Get( *channel ) - .SetDisplay(WaveTrackView::WaveTrackDisplay(id)); + .SetDisplay( WaveTrackView::Display{ id } ); } AudacityProject *const project = &mpData->project; @@ -886,7 +917,7 @@ void WaveTrackMenuTable::OnSpectrogramSettings(wxCommandEvent &) // factories.push_back(WaveformPrefsFactory( pTrack )); factories.push_back(SpectrumPrefsFactory( pTrack )); const int page = - // (pTrack->GetDisplay() == WaveTrack::Spectrum) ? 1 : + // (pTrack->GetDisplay() == WaveTrackViewConstants::Spectrum) ? 1 : 0; auto title = XO("%s:").Format( pTrack->GetName() ); diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp index 1215c5f0a..a2c20c6cc 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp @@ -40,6 +40,53 @@ Paul Licameli split from TrackPanel.cpp #include "../../../ui/ButtonHandle.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 { using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >; @@ -842,12 +889,13 @@ WaveTrackView::DoDetailedHitTest return { false, results }; } -auto WaveTrackView::GetDisplays() const -> std::vector +auto WaveTrackView::GetDisplays() const + -> std::vector< WaveTrackSubView::Type > { BuildSubViews(); // 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; size_t ii = 0; WaveTrackSubViews::ForEach( [&]( const WaveTrackSubView &subView ){ @@ -857,24 +905,24 @@ auto WaveTrackView::GetDisplays() const -> std::vector ++ii; } ); std::sort( pairs.begin(), pairs.end() ); - std::vector results; + std::vector< WaveTrackSubView::Type > results; for ( const auto &pair : pairs ) results.push_back( pair.second ); return results; } -void WaveTrackView::SetDisplay(WaveTrackDisplay display, bool exclusive) +void WaveTrackView::SetDisplay(Display display, bool exclusive) { BuildSubViews(); DoSetDisplay( display, exclusive ); } -bool WaveTrackView::ToggleSubView(WaveTrackDisplay display) +bool WaveTrackView::ToggleSubView(Display display) { size_t ii = 0; size_t found = 0; if ( WaveTrackSubViews::FindIf( [&]( const WaveTrackSubView &subView ) { - if ( subView.SubViewType() == display ) { + if ( subView.SubViewType().id == display ) { found = ii; return true; } @@ -927,7 +975,7 @@ bool WaveTrackView::ToggleSubView(WaveTrackDisplay display) // If exclusive, make the chosen view take up all the height. Else, // partition equally, putting the specified view on top. // 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. // 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; std::vector< std::pair< WaveTrackViewConstants::Display, size_t > > pairs; 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() ); diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.h b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.h index a60d1ed84..d0a42d60b 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.h +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.h @@ -13,19 +13,44 @@ Paul Licameli split from class WaveTrack #include "../../../ui/CommonTrackView.h" #include "../../../../ClientData.h" +#include "audacity/ComponentInterface.h" namespace WaveTrackViewConstants{ enum Display : int; } class CutlineHandle; +class TranslatableString; class WaveTrack; class WaveTrackView; class WaveTrackSubView : public CommonTrackView { 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 WaveTrackSubView( WaveTrackView &waveTrackView ); - virtual WaveTrackViewConstants::Display SubViewType() const = 0; + virtual const Type &SubViewType() const = 0; std::pair< bool, // if true, hit-testing is finished @@ -67,6 +92,8 @@ class WaveTrackView final WaveTrackView &operator=( const WaveTrackView& ) = delete; public: + using Display = WaveTrackViewConstants::Display; + static WaveTrackView &Get( WaveTrack &track ); static const WaveTrackView &Get( const WaveTrack &track ); @@ -91,10 +118,8 @@ public: const std::shared_ptr &wt, CommonTrackView &view); - using WaveTrackDisplay = WaveTrackViewConstants::Display; - - std::vector GetDisplays() const; - void SetDisplay(WaveTrackDisplay display, bool exclusive = true); + std::vector< WaveTrackSubView::Type > GetDisplays() const; + void SetDisplay(Display display, bool exclusive = true); const WaveTrackSubViewPlacements &SavePlacements() const { return mPlacements; } @@ -103,7 +128,7 @@ public: // Return true if successful. Fails if you try to toggle off the only // sub-view. - bool ToggleSubView( WaveTrackDisplay id ); + bool ToggleSubView( Display id ); // Get all the sub-views, in a sequence that is unspecified but in // correspondence with the result of SavePlacements @@ -117,7 +142,7 @@ public: private: void BuildSubViews() const; - void DoSetDisplay(WaveTrackDisplay display, bool exclusive = true); + void DoSetDisplay(Display display, bool exclusive = true); // TrackPanelDrawable implementation void Draw( diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp index b2f2d9071..6ba32ab2a 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveformView.cpp @@ -36,6 +36,13 @@ Paul Licameli split from WaveTrackView.cpp #include #include +static WaveTrackSubView::Type sType{ + WaveTrackViewConstants::Waveform, + { wxT("Waveform"), XO("Wa&veform") } +}; + +static WaveTrackSubView::RegisteredType reg{ sType }; + WaveformView::~WaveformView() = default; std::vector WaveformView::DetailedHitTest( @@ -119,9 +126,9 @@ void WaveformView::DoSetMinimized( bool minimized ) TrackView::DoSetMinimized( minimized ); } -WaveTrackViewConstants::Display WaveformView::SubViewType() const +auto WaveformView::SubViewType() const -> const Type & { - return WaveTrackViewConstants::Waveform; + return sType; } std::shared_ptr WaveformView::DoGetVRulerControls() diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveformView.h b/src/tracks/playabletrack/wavetrack/ui/WaveformView.h index 7d91867e9..072fa2901 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveformView.h +++ b/src/tracks/playabletrack/wavetrack/ui/WaveformView.h @@ -26,7 +26,7 @@ public: using WaveTrackSubView::WaveTrackSubView; ~WaveformView() override; - virtual WaveTrackViewConstants::Display SubViewType() const override; + const Type &SubViewType() const override; std::shared_ptr DoGetVRulerControls() override;