mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-02 08:59:28 +02:00
Don't hard-code the exhaustive list of sub-view types...
... in Wave track context menu and SetTrackVisualsCommand Instead, discover them through a registry. This eliminates some duplication of string constants and prepares for non-intrusive generalization to more kinds of sub-views. This makes the command agnostic about which subview types are known, but the context menu still has special case treatment for Spectrogram Settings and Wave Colors.
This commit is contained in:
parent
fb8ba0ce43
commit
36aad4d1c6
@ -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(); }
|
||||||
|
|
||||||
|
@ -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 ) );
|
||||||
|
|
||||||
|
{
|
||||||
|
auto symbols = DiscoverSubViewTypes();
|
||||||
|
auto typeNames = transform_container<TranslatableStrings>(
|
||||||
|
symbols, std::mem_fn( &EnumValueSymbol::Stripped ) );
|
||||||
S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType,
|
S.Optional( bHasDisplayType ).TieChoice( XO("Display:"), mDisplayType,
|
||||||
Msgids( kDisplayTypeStrings, nDisplayTypes ) );
|
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) ?
|
||||||
|
@ -30,6 +30,11 @@ Paul Licameli split from WaveTrackView.cpp
|
|||||||
#include <wx/dcmemory.h>
|
#include <wx/dcmemory.h>
|
||||||
#include <wx/graphics.h>
|
#include <wx/graphics.h>
|
||||||
|
|
||||||
|
static WaveTrackSubView::RegisteredType reg{ {
|
||||||
|
WaveTrackViewConstants::Spectrum,
|
||||||
|
{ wxT("Spectrogram"), XO("&Spectrogram") }
|
||||||
|
} };
|
||||||
|
|
||||||
SpectrumView::~SpectrumView() = default;
|
SpectrumView::~SpectrumView() = default;
|
||||||
|
|
||||||
bool SpectrumView::IsSpectral() const
|
bool SpectrumView::IsSpectral() const
|
||||||
|
@ -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 == 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)
|
||||||
|
|
||||||
|
int id = OnSetDisplayId;
|
||||||
|
for ( const auto &type : AllTypes() ) {
|
||||||
if ( view.GetMultiView() ) {
|
if ( view.GetMultiView() ) {
|
||||||
POPUP_MENU_CHECK_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay)
|
POPUP_MENU_CHECK_ITEM(id++, type.name.Msgid(), OnSetDisplay)
|
||||||
POPUP_MENU_CHECK_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
POPUP_MENU_RADIO_ITEM(OnWaveformID, XO("Wa&veform"), OnSetDisplay)
|
POPUP_MENU_RADIO_ITEM(id++, type.name.Msgid(), OnSetDisplay)
|
||||||
POPUP_MENU_RADIO_ITEM(OnSpectrumID, XO("&Spectrogram"), OnSetDisplay)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
POPUP_MENU_ITEM(OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings)
|
POPUP_MENU_ITEM(OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings)
|
||||||
@ -799,19 +834,12 @@ 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::Display 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() ) {
|
||||||
@ -887,7 +915,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() );
|
||||||
|
@ -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 > >;
|
||||||
|
@ -13,16 +13,39 @@ 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;
|
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 );
|
||||||
|
@ -36,6 +36,11 @@ Paul Licameli split from WaveTrackView.cpp
|
|||||||
#include <wx/graphics.h>
|
#include <wx/graphics.h>
|
||||||
#include <wx/dc.h>
|
#include <wx/dc.h>
|
||||||
|
|
||||||
|
static WaveTrackSubView::RegisteredType reg{ {
|
||||||
|
WaveTrackViewConstants::Waveform,
|
||||||
|
{ wxT("Waveform"), XO("Wa&veform") }
|
||||||
|
} };
|
||||||
|
|
||||||
WaveformView::~WaveformView() = default;
|
WaveformView::~WaveformView() = default;
|
||||||
|
|
||||||
std::vector<UIHandlePtr> WaveformView::DetailedHitTest(
|
std::vector<UIHandlePtr> WaveformView::DetailedHitTest(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user