mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-30 07:29:29 +02:00
Preliminaries before a registration system for track popup menus
This commit is contained in:
commit
52bc74861a
@ -72,9 +72,9 @@ enum
|
||||
};
|
||||
|
||||
BEGIN_POPUP_MENU(LabelTrackMenuTable)
|
||||
BEGIN_POPUP_MENU_SECTION( "Basic" )
|
||||
POPUP_MENU_ITEM( "Font", OnSetFontID, XO("&Font..."), OnSetFont)
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "Basic" );
|
||||
AppendItem( "Font", OnSetFontID, XO("&Font..."), POPUP_MENU_FN( OnSetFont ) );
|
||||
EndSection();
|
||||
END_POPUP_MENU()
|
||||
|
||||
void LabelTrackMenuTable::OnSetFont(wxCommandEvent &)
|
||||
|
@ -131,10 +131,10 @@ void NoteTrackMenuTable::OnChangeOctave(wxCommandEvent &event)
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(NoteTrackMenuTable)
|
||||
BEGIN_POPUP_MENU_SECTION( "Basic" )
|
||||
POPUP_MENU_ITEM( "Up", OnUpOctaveID, XO("Up &Octave"), OnChangeOctave)
|
||||
POPUP_MENU_ITEM( "Down", OnDownOctaveID, XO("Down Octa&ve"), OnChangeOctave)
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "Basic" );
|
||||
AppendItem( "Up", OnUpOctaveID, XO("Up &Octave"), POPUP_MENU_FN( OnChangeOctave ) );
|
||||
AppendItem( "Down", OnDownOctaveID, XO("Down Octa&ve"), POPUP_MENU_FN( OnChangeOctave ) );
|
||||
EndSection();
|
||||
END_POPUP_MENU()
|
||||
|
||||
PopupMenuTable *NoteTrackControls::GetMenuExtension(Track *)
|
||||
|
@ -256,24 +256,24 @@ void NoteTrackVRulerMenuTable::OnZoom( int iZoomCode ){
|
||||
|
||||
BEGIN_POPUP_MENU(NoteTrackVRulerMenuTable)
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Zoom" )
|
||||
BEGIN_POPUP_MENU_SECTION( "Basic" )
|
||||
POPUP_MENU_ITEM( "Reset", OnZoomResetID, XO("Zoom Reset\tShift-Right-Click"), OnZoomReset)
|
||||
POPUP_MENU_ITEM( "Max", OnZoomMaxID, XO("Max Zoom"), OnZoomMax)
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "Zoom" );
|
||||
BeginSection( "Basic" );
|
||||
AppendItem( "Reset", OnZoomResetID, XO("Zoom Reset\tShift-Right-Click"), POPUP_MENU_FN( OnZoomReset ) );
|
||||
AppendItem( "Max", OnZoomMaxID, XO("Max Zoom"), POPUP_MENU_FN( OnZoomMax ) );
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "InOut" )
|
||||
POPUP_MENU_ITEM( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical)
|
||||
POPUP_MENU_ITEM( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"), OnZoomOutVertical)
|
||||
END_POPUP_MENU_SECTION()
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "InOut" );
|
||||
AppendItem( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"), POPUP_MENU_FN( OnZoomInVertical ) );
|
||||
AppendItem( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"), POPUP_MENU_FN( OnZoomOutVertical ) );
|
||||
EndSection();
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Pan" )
|
||||
BEGIN_POPUP_MENU_SECTION( "Octaves" )
|
||||
POPUP_MENU_ITEM( "Up", OnUpOctaveID, XO("Up &Octave"), OnUpOctave)
|
||||
POPUP_MENU_ITEM( "Down", OnDownOctaveID, XO("Down Octa&ve"), OnDownOctave)
|
||||
END_POPUP_MENU_SECTION()
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "Pan" );
|
||||
BeginSection( "Octaves" );
|
||||
AppendItem( "Up", OnUpOctaveID, XO("Up &Octave"), POPUP_MENU_FN( OnUpOctave) );
|
||||
AppendItem( "Down", OnDownOctaveID, XO("Down Octa&ve"), POPUP_MENU_FN( OnDownOctave ) );
|
||||
EndSection();
|
||||
EndSection();
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
|
@ -265,36 +265,40 @@ PopupMenuTable &SpectrumVRulerMenuTable::Instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
void SpectrumVRulerMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrackVRulerMenuTable::InitMenu(pMenu);
|
||||
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
const int id =
|
||||
OnFirstSpectrumScaleID + (int)(wt->GetSpectrogramSettings().scaleType);
|
||||
pMenu->Check(id, true);
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(SpectrumVRulerMenuTable)
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Scales" )
|
||||
BeginSection( "Scales" );
|
||||
{
|
||||
const auto & names = SpectrogramSettings::GetScaleNames();
|
||||
for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
|
||||
POPUP_MENU_RADIO_ITEM( names[ii].Internal(),
|
||||
AppendRadioItem( names[ii].Internal(),
|
||||
OnFirstSpectrumScaleID + ii, names[ii].Msgid(),
|
||||
OnSpectrumScaleType);
|
||||
POPUP_MENU_FN( OnSpectrumScaleType ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
WaveTrack *const wt =
|
||||
static_cast<SpectrumVRulerMenuTable&>( handler )
|
||||
.mpData->pTrack;
|
||||
if ( id ==
|
||||
OnFirstSpectrumScaleID +
|
||||
(int)(wt->GetSpectrogramSettings().scaleType ) )
|
||||
menu.Check(id, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Zoom" )
|
||||
POPUP_MENU_ITEM( "Reset", OnZoomResetID, XO("Zoom Reset"), OnZoomReset)
|
||||
POPUP_MENU_ITEM( "Fit", OnZoomFitVerticalID, XO("Zoom to Fit\tShift-Right-Click"), OnZoomFitVertical)
|
||||
POPUP_MENU_ITEM( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical)
|
||||
POPUP_MENU_ITEM( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"), OnZoomOutVertical)
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "Zoom" );
|
||||
AppendItem( "Reset", OnZoomResetID, XO("Zoom Reset"),
|
||||
POPUP_MENU_FN( OnZoomReset ) );
|
||||
AppendItem( "Fit", OnZoomFitVerticalID, XO("Zoom to Fit\tShift-Right-Click"),
|
||||
POPUP_MENU_FN( OnZoomFitVertical ) );
|
||||
AppendItem( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"),
|
||||
POPUP_MENU_FN( OnZoomInVertical ) );
|
||||
AppendItem( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"),
|
||||
POPUP_MENU_FN( OnZoomOutVertical ) );
|
||||
EndSection();
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
|
@ -85,8 +85,6 @@ public:
|
||||
static PopupMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void OnSpectrumScaleType(wxCommandEvent &evt);
|
||||
};
|
||||
|
||||
|
@ -43,22 +43,6 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include <wx/frame.h>
|
||||
#include <wx/sizer.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Puts a check mark at a given position in a menu.
|
||||
template<typename Pred>
|
||||
void SetMenuChecks(wxMenu & menu, const Pred &pred)
|
||||
{
|
||||
for (auto &item : menu.GetMenuItems())
|
||||
{
|
||||
if (item->IsCheckable()) {
|
||||
auto id = item->GetId();
|
||||
menu.Check(id, pred(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaveTrackControls::~WaveTrackControls()
|
||||
{
|
||||
}
|
||||
@ -148,21 +132,38 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
using ValueFinder = std::function< int( WaveTrack& ) >;
|
||||
|
||||
// A function that makes functions that check and enable sub-menu items,
|
||||
// parametrized by how you get the relevant value from a track's settings
|
||||
template< typename Table >
|
||||
PopupMenuTableEntry::InitFunction initFn( const ValueFinder &findValue )
|
||||
{
|
||||
return [findValue]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto pData = static_cast<Table&>( handler ).mpData;
|
||||
const auto pTrack = static_cast<WaveTrack*>(pData->pTrack);
|
||||
auto &project = pData->project;
|
||||
bool unsafe = ProjectAudioIO::Get( project ).IsAudioActive();
|
||||
|
||||
menu.Check( id, id == findValue( *pTrack ) );
|
||||
menu.Enable( id, !unsafe );
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
class WaveColorMenuTable : public PopupMenuTable
|
||||
struct WaveColorMenuTable : PopupMenuTable
|
||||
{
|
||||
WaveColorMenuTable()
|
||||
: PopupMenuTable( "WaveColor", XO("&Wave Color") )
|
||||
{}
|
||||
DECLARE_POPUP_MENU(WaveColorMenuTable);
|
||||
|
||||
public:
|
||||
static WaveColorMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitUserData(void *pUserData) override;
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
@ -171,7 +172,7 @@ private:
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
int IdOfWaveColor(int WaveColor);
|
||||
static int IdOfWaveColor(int WaveColor);
|
||||
void OnWaveColorChange(wxCommandEvent & event);
|
||||
};
|
||||
|
||||
@ -186,34 +187,27 @@ void WaveColorMenuTable::InitUserData(void *pUserData)
|
||||
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void WaveColorMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
auto WaveColorId = IdOfWaveColor( pTrack->GetWaveColorIndex());
|
||||
SetMenuChecks(*pMenu, [=](int id){ return id == WaveColorId; });
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
bool unsafe = ProjectAudioIO::Get( *project ).IsAudioActive();
|
||||
for (int i = OnInstrument1ID; i <= OnInstrument4ID; i++) {
|
||||
pMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
const TranslatableString GetWaveColorStr(int colorIndex)
|
||||
{
|
||||
return XO("Instrument %i").Format( colorIndex+1 );
|
||||
}
|
||||
|
||||
|
||||
BEGIN_POPUP_MENU(WaveColorMenuTable)
|
||||
POPUP_MENU_RADIO_ITEM( "Instrument1", OnInstrument1ID,
|
||||
GetWaveColorStr(0), OnWaveColorChange)
|
||||
POPUP_MENU_RADIO_ITEM( "Instrument2", OnInstrument2ID,
|
||||
GetWaveColorStr(1), OnWaveColorChange)
|
||||
POPUP_MENU_RADIO_ITEM( "Instrument3", OnInstrument3ID,
|
||||
GetWaveColorStr(2), OnWaveColorChange)
|
||||
POPUP_MENU_RADIO_ITEM( "Instrument4", OnInstrument4ID,
|
||||
GetWaveColorStr(3), OnWaveColorChange)
|
||||
static const auto fn = initFn< WaveColorMenuTable >(
|
||||
[]( WaveTrack &track ){
|
||||
return IdOfWaveColor( track.GetWaveColorIndex() );
|
||||
}
|
||||
);
|
||||
|
||||
AppendRadioItem( "Instrument1", OnInstrument1ID,
|
||||
GetWaveColorStr(0), POPUP_MENU_FN( OnWaveColorChange ), fn );
|
||||
AppendRadioItem( "Instrument2", OnInstrument2ID,
|
||||
GetWaveColorStr(1), POPUP_MENU_FN( OnWaveColorChange ), fn );
|
||||
AppendRadioItem( "Instrument3", OnInstrument3ID,
|
||||
GetWaveColorStr(2), POPUP_MENU_FN( OnWaveColorChange ), fn );
|
||||
AppendRadioItem( "Instrument4", OnInstrument4ID,
|
||||
GetWaveColorStr(3), POPUP_MENU_FN( OnWaveColorChange ), fn );
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
/// Converts a WaveColor enumeration to a wxWidgets menu item Id.
|
||||
@ -249,19 +243,16 @@ void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
class FormatMenuTable : public PopupMenuTable
|
||||
struct FormatMenuTable : PopupMenuTable
|
||||
{
|
||||
FormatMenuTable()
|
||||
: PopupMenuTable{ "SampleFormat", XO("&Format") }
|
||||
{}
|
||||
DECLARE_POPUP_MENU(FormatMenuTable);
|
||||
|
||||
public:
|
||||
static FormatMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitUserData(void *pUserData) override;
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
@ -270,7 +261,7 @@ private:
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
int IdOfFormat(int format);
|
||||
static int IdOfFormat(int format);
|
||||
|
||||
void OnFormatChange(wxCommandEvent & event);
|
||||
};
|
||||
@ -286,26 +277,21 @@ void FormatMenuTable::InitUserData(void *pUserData)
|
||||
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void FormatMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
auto formatId = IdOfFormat(pTrack->GetSampleFormat());
|
||||
SetMenuChecks(*pMenu, [=](int id){ return id == formatId; });
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
bool unsafe = ProjectAudioIO::Get( *project ).IsAudioActive();
|
||||
for (int i = On16BitID; i <= OnFloatID; i++) {
|
||||
pMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(FormatMenuTable)
|
||||
POPUP_MENU_RADIO_ITEM( "16Bit", On16BitID,
|
||||
GetSampleFormatStr(int16Sample), OnFormatChange)
|
||||
POPUP_MENU_RADIO_ITEM("24Bit", On24BitID,
|
||||
GetSampleFormatStr( int24Sample), OnFormatChange)
|
||||
POPUP_MENU_RADIO_ITEM( "Float", OnFloatID,
|
||||
GetSampleFormatStr(floatSample), OnFormatChange)
|
||||
static const auto fn = initFn< FormatMenuTable >(
|
||||
[]( WaveTrack &track ){
|
||||
return IdOfFormat( track.GetSampleFormat() );
|
||||
}
|
||||
);
|
||||
|
||||
AppendRadioItem( "16Bit", On16BitID,
|
||||
GetSampleFormatStr(int16Sample), POPUP_MENU_FN( OnFormatChange ), fn );
|
||||
AppendRadioItem("24Bit", On24BitID,
|
||||
GetSampleFormatStr( int24Sample), POPUP_MENU_FN( OnFormatChange ), fn );
|
||||
AppendRadioItem( "Float", OnFloatID,
|
||||
GetSampleFormatStr(floatSample), POPUP_MENU_FN( OnFormatChange ), fn );
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
/// Converts a format enumeration to a wxWidgets menu item Id.
|
||||
@ -372,19 +358,16 @@ void FormatMenuTable::OnFormatChange(wxCommandEvent & event)
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
class RateMenuTable : public PopupMenuTable
|
||||
struct RateMenuTable : PopupMenuTable
|
||||
{
|
||||
RateMenuTable()
|
||||
: PopupMenuTable{ "SampleRate", XO("Rat&e") }
|
||||
{}
|
||||
DECLARE_POPUP_MENU(RateMenuTable);
|
||||
|
||||
public:
|
||||
static RateMenuTable &Instance();
|
||||
|
||||
private:
|
||||
void InitUserData(void *pUserData) override;
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
@ -393,7 +376,7 @@ private:
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
int IdOfRate(int rate);
|
||||
static int IdOfRate(int rate);
|
||||
void SetRate(WaveTrack * pTrack, double rate);
|
||||
|
||||
void OnRateChange(wxCommandEvent & event);
|
||||
@ -411,36 +394,30 @@ void RateMenuTable::InitUserData(void *pUserData)
|
||||
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void RateMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
const auto rateId = IdOfRate((int)pTrack->GetRate());
|
||||
SetMenuChecks(*pMenu, [=](int id){ return id == rateId; });
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
bool unsafe = ProjectAudioIO::Get( *project ).IsAudioActive();
|
||||
for (int i = OnRate8ID; i <= OnRateOtherID; i++) {
|
||||
pMenu->Enable(i, !unsafe);
|
||||
}
|
||||
}
|
||||
|
||||
// Because of Bug 1780 we can't use POPUP_MENU_RADIO_ITEM
|
||||
// Because of Bug 1780 we can't use AppendRadioItem
|
||||
// If we did, we'd get no message when clicking on Other...
|
||||
// when it is already selected.
|
||||
BEGIN_POPUP_MENU(RateMenuTable)
|
||||
POPUP_MENU_CHECK_ITEM( "8000", OnRate8ID, XO("8000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "11025", OnRate11ID, XO("11025 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "16000", OnRate16ID, XO("16000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "22050", OnRate22ID, XO("22050 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "44100", OnRate44ID, XO("44100 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "48000", OnRate48ID, XO("48000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "88200", OnRate88ID, XO("88200 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "96000", OnRate96ID, XO("96000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "176400", OnRate176ID, XO("176400 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "192000", OnRate192ID, XO("192000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "352800", OnRate352ID, XO("352800 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "384000", OnRate384ID, XO("384000 Hz"), OnRateChange)
|
||||
POPUP_MENU_CHECK_ITEM( "Other", OnRateOtherID, XO("&Other..."), OnRateOther)
|
||||
static const auto fn = initFn< RateMenuTable >(
|
||||
[]( WaveTrack &track ){
|
||||
return IdOfRate( (int)track.GetRate() );
|
||||
}
|
||||
);
|
||||
|
||||
AppendCheckItem( "8000", OnRate8ID, XO("8000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "11025", OnRate11ID, XO("11025 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "16000", OnRate16ID, XO("16000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "22050", OnRate22ID, XO("22050 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "44100", OnRate44ID, XO("44100 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "48000", OnRate48ID, XO("48000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "88200", OnRate88ID, XO("88200 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "96000", OnRate96ID, XO("96000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "176400", OnRate176ID, XO("176400 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "192000", OnRate192ID, XO("192000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "352800", OnRate352ID, XO("352800 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "384000", OnRate384ID, XO("384000 Hz"), POPUP_MENU_FN( OnRateChange ), fn );
|
||||
AppendCheckItem( "Other", OnRateOtherID, XO("&Other..."), POPUP_MENU_FN( OnRateOther ), fn );
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
const int nRates = 12;
|
||||
@ -573,19 +550,16 @@ void RateMenuTable::OnRateOther(wxCommandEvent &)
|
||||
|
||||
//=============================================================================
|
||||
// Class defining common command handlers for mono and stereo tracks
|
||||
class WaveTrackMenuTable : public PopupMenuTable
|
||||
struct WaveTrackMenuTable : PopupMenuTable
|
||||
{
|
||||
public:
|
||||
static WaveTrackMenuTable &Instance( Track * pTrack);
|
||||
Track * mpTrack{};
|
||||
|
||||
protected:
|
||||
WaveTrackMenuTable()
|
||||
: PopupMenuTable{ "WaveTrack" }
|
||||
{}
|
||||
|
||||
void InitUserData(void *pUserData) override;
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
@ -639,149 +613,84 @@ static std::vector<WaveTrackSubViewType> AllTypes()
|
||||
return result;
|
||||
}
|
||||
|
||||
void WaveTrackMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
std::vector<int> checkedIds;
|
||||
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
auto multiView = view.GetMultiView();
|
||||
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 );
|
||||
|
||||
// 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 )
|
||||
// Bug2275 residual
|
||||
// Disable the checking-off of the only sub-view
|
||||
pMenu->Enable( uniqueDisplay, false );
|
||||
|
||||
// Bug 1253. Shouldn't open preferences if audio is busy.
|
||||
// We can't change them on the fly yet anyway.
|
||||
auto gAudioIO = AudioIOBase::Get();
|
||||
if ( hasSpectrum )
|
||||
pMenu->Enable(OnSpectrogramSettingsID, !gAudioIO->IsBusy());
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
auto &tracks = TrackList::Get( *project );
|
||||
bool unsafe = RealtimeEffectManager::Get().RealtimeIsActive() &&
|
||||
ProjectAudioIO::Get( *project ).IsAudioActive();
|
||||
|
||||
auto nChannels = TrackList::Channels(pTrack).size();
|
||||
const bool isMono = ( nChannels == 1 );
|
||||
const bool isStereo = ( nChannels == 2 );
|
||||
// Maybe more than stereo tracks some time?
|
||||
|
||||
if ( isMono )
|
||||
{
|
||||
WaveTrack *const pTrack2 = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
auto next = * ++ tracks.Find(pTrack2);
|
||||
|
||||
if (isMono) {
|
||||
const bool canMakeStereo =
|
||||
(next &&
|
||||
TrackList::Channels(next).size() == 1 &&
|
||||
track_cast<WaveTrack*>(next));
|
||||
|
||||
pMenu->Enable(OnMergeStereoID, canMakeStereo && !unsafe);
|
||||
|
||||
int itemId;
|
||||
switch (pTrack2->GetChannel()) {
|
||||
case Track::LeftChannel:
|
||||
itemId = OnChannelLeftID;
|
||||
break;
|
||||
case Track::RightChannel:
|
||||
itemId = OnChannelRightID;
|
||||
break;
|
||||
default:
|
||||
itemId = OnChannelMonoID;
|
||||
break;
|
||||
}
|
||||
checkedIds.push_back(itemId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pMenu->Enable(OnMergeStereoID, false);
|
||||
}
|
||||
|
||||
SetMenuChecks(*pMenu, [&](int id){
|
||||
auto end = checkedIds.end();
|
||||
return end != std::find(checkedIds.begin(), end, id);
|
||||
});
|
||||
|
||||
// Enable this only for properly stereo tracks:
|
||||
pMenu->Enable(OnSwapChannelsID, isStereo && !unsafe);
|
||||
pMenu->Enable(OnSplitStereoID, !isMono && !unsafe);
|
||||
|
||||
#ifndef EXPERIMENTAL_DA
|
||||
// Can be achieved by split stereo and then dragging pan slider.
|
||||
pMenu->Enable(OnSplitStereoMonoID, !isMono && !unsafe);
|
||||
#endif
|
||||
|
||||
// Several menu items no longer needed....
|
||||
#if 0
|
||||
pMenu->Enable(OnChannelMonoID, isMono);
|
||||
pMenu->Enable(OnChannelLeftID, isMono);
|
||||
pMenu->Enable(OnChannelRightID, isMono);
|
||||
#endif
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
// Functions usable "now" (list population time) and also "later"
|
||||
// (in callbacks to check and disable items)
|
||||
static const auto findTrack =
|
||||
[]( PopupMenuHandler &handler ) -> WaveTrack & {
|
||||
return *static_cast< WaveTrack* >(
|
||||
static_cast< WaveTrackMenuTable& >( handler ).mpData->pTrack);
|
||||
};
|
||||
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpTrack);
|
||||
static const auto isMono =
|
||||
[]( PopupMenuHandler &handler ) -> bool {
|
||||
return 1 == TrackList::Channels( &findTrack( handler ) ).size();
|
||||
};
|
||||
|
||||
static const auto isUnsafe =
|
||||
[]( PopupMenuHandler &handler ) -> bool {
|
||||
auto &project =
|
||||
static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
|
||||
return RealtimeEffectManager::Get().RealtimeIsActive() &&
|
||||
ProjectAudioIO::Get( project ).IsAudioActive();
|
||||
};
|
||||
|
||||
const auto pTrack = &findTrack( *this );
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "SubViews" )
|
||||
BeginSection( "SubViews" );
|
||||
if ( WaveTrackSubViews::slots() > 1 )
|
||||
POPUP_MENU_CHECK_ITEM( "MultiView", OnMultiViewID, XO("&Multi-view"), OnMultiView)
|
||||
AppendCheckItem( "MultiView", OnMultiViewID, XO("&Multi-view"),
|
||||
POPUP_MENU_FN( OnMultiView ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto &track = findTrack( handler );
|
||||
const auto &view = WaveTrackView::Get( track );
|
||||
menu.Check( id, view.GetMultiView() );
|
||||
}
|
||||
);
|
||||
|
||||
int id = OnSetDisplayId;
|
||||
for ( const auto &type : AllTypes() ) {
|
||||
static const auto initFn = []( bool radio ){ return
|
||||
[radio]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
// Find all known sub-view types
|
||||
const auto allTypes = AllTypes();
|
||||
|
||||
// How to convert a type to a menu item id
|
||||
const auto IdForType =
|
||||
[&allTypes]( const WaveTrackSubViewType &type ) -> int {
|
||||
const auto begin = allTypes.begin();
|
||||
return OnSetDisplayId +
|
||||
(std::find( begin, allTypes.end(), type ) - begin);
|
||||
};
|
||||
|
||||
auto &track = findTrack( handler );
|
||||
const auto &view = WaveTrackView::Get( track );
|
||||
|
||||
const auto displays = view.GetDisplays();
|
||||
const auto end = displays.end();
|
||||
bool check = (end !=
|
||||
std::find_if( displays.begin(), end,
|
||||
[&]( const WaveTrackSubViewType &type ){
|
||||
return id == IdForType( type ); } ) );
|
||||
menu.Check( id, check );
|
||||
|
||||
// Bug2275 residual
|
||||
// Disable the checking-off of the only sub-view
|
||||
if ( !radio && displays.size() == 1 && check )
|
||||
menu.Enable( id, false );
|
||||
};
|
||||
};
|
||||
if ( view.GetMultiView() ) {
|
||||
POPUP_MENU_CHECK_ITEM( type.name.Internal(), id++, type.name.Msgid(), OnSetDisplay)
|
||||
AppendCheckItem( type.name.Internal(), id++, type.name.Msgid(),
|
||||
POPUP_MENU_FN( OnSetDisplay ), initFn( false ) );
|
||||
}
|
||||
else {
|
||||
POPUP_MENU_RADIO_ITEM( type.name.Internal(), id++, type.name.Msgid(), OnSetDisplay)
|
||||
AppendRadioItem( type.name.Internal(), id++, type.name.Msgid(),
|
||||
POPUP_MENU_FN( OnSetDisplay ), initFn( true ) );
|
||||
}
|
||||
}
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
if ( pTrack ) {
|
||||
|
||||
@ -791,9 +700,9 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} }
|
||||
) );
|
||||
if( hasWaveform ){
|
||||
BEGIN_POPUP_MENU_SECTION( "WaveColor" )
|
||||
BeginSection( "WaveColor" );
|
||||
POPUP_MENU_SUB_MENU( "WaveColor", WaveColorMenuTable, mpData )
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
}
|
||||
|
||||
bool hasSpectrum = (displays.end() != std::find(
|
||||
@ -801,36 +710,98 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
|
||||
) );
|
||||
if( hasSpectrum ){
|
||||
BEGIN_POPUP_MENU_SECTION( "SpectrogramSettings" )
|
||||
POPUP_MENU_ITEM( "SpectrogramSettings", OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), OnSpectrogramSettings)
|
||||
END_POPUP_MENU_SECTION()
|
||||
// In future, we might move this 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.)
|
||||
|
||||
BeginSection( "SpectrogramSettings" );
|
||||
AppendItem( "SpectrogramSettings", OnSpectrogramSettingsID, XO("S&pectrogram Settings..."), POPUP_MENU_FN( OnSpectrogramSettings ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
// Bug 1253. Shouldn't open preferences if audio is busy.
|
||||
// We can't change them on the fly yet anyway.
|
||||
auto gAudioIO = AudioIOBase::Get();
|
||||
menu.Enable(id, !gAudioIO->IsBusy());
|
||||
}
|
||||
);
|
||||
EndSection();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Channels" )
|
||||
BeginSection( "Channels" );
|
||||
// If these are enabled again, choose a hot key for Mono that does not conflict
|
||||
// with Multi View
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelMonoID, XO("&Mono"), OnChannelChange)
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelLeftID, XO("&Left Channel"), OnChannelChange)
|
||||
// POPUP_MENU_RADIO_ITEM(OnChannelRightID, XO("R&ight Channel"), OnChannelChange)
|
||||
POPUP_MENU_ITEM( "MakeStereo", OnMergeStereoID, XO("Ma&ke Stereo Track"), OnMergeStereo)
|
||||
// AppendRadioItem(OnChannelMonoID, XO("&Mono"),
|
||||
// POPUP_MENU_FN( OnChannelChange ),
|
||||
// []( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
// menu.Enable( id, isMono( handler ) );
|
||||
// menu.Check( id, findTrack( handler ).GetChannel() == Track::MonoChannel );
|
||||
// }
|
||||
// );
|
||||
// AppendRadioItem(OnChannelLeftID, XO("&Left Channel"),
|
||||
// POPUP_MENU_FN( OnChannelChange ),
|
||||
// []( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
// menu.Enable( id, isMono( handler ) );
|
||||
// menu.Check( id, findTrack( handler ).GetChannel() == Track::LeftChannel );
|
||||
// }
|
||||
// );
|
||||
// AppendRadioItem(OnChannelRightID, XO("R&ight Channel"),
|
||||
// POPUP_MENU_FN( OnChannelChange ),
|
||||
// []( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
// menu.Enable( id, isMono( handler ) );
|
||||
// menu.Check( id, findTrack( handler ).GetChannel() == Track::RightChannel );
|
||||
// }
|
||||
// );
|
||||
AppendItem( "MakeStereo", OnMergeStereoID, XO("Ma&ke Stereo Track"),
|
||||
POPUP_MENU_FN( OnMergeStereo ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
bool canMakeStereo = !isUnsafe( handler ) && isMono( handler );
|
||||
if ( canMakeStereo ) {
|
||||
AudacityProject &project =
|
||||
static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
|
||||
auto &tracks = TrackList::Get( project );
|
||||
auto &track = findTrack( handler );
|
||||
auto next = * ++ tracks.Find(&track);
|
||||
canMakeStereo =
|
||||
(next &&
|
||||
TrackList::Channels(next).size() == 1 &&
|
||||
track_cast<WaveTrack*>(next));
|
||||
}
|
||||
menu.Enable( id, canMakeStereo );
|
||||
}
|
||||
);
|
||||
|
||||
POPUP_MENU_ITEM( "Swap", OnSwapChannelsID, XO("Swap Stereo &Channels"), OnSwapChannels)
|
||||
POPUP_MENU_ITEM( "Split", OnSplitStereoID, XO("Spl&it Stereo Track"), OnSplitStereo)
|
||||
AppendItem( "Swap", OnSwapChannelsID, XO("Swap Stereo &Channels"),
|
||||
POPUP_MENU_FN( OnSwapChannels ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
bool isStereo =
|
||||
2 == TrackList::Channels( &findTrack( handler ) ).size();
|
||||
menu.Enable( id, isStereo && !isUnsafe( handler ) );
|
||||
}
|
||||
);
|
||||
|
||||
static const auto enableSplitStereo =
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
menu.Enable( id, !isMono( handler ) && !isUnsafe( handler ) );
|
||||
};
|
||||
|
||||
AppendItem( "Split", OnSplitStereoID, XO("Spl&it Stereo Track"),
|
||||
POPUP_MENU_FN( OnSplitStereo ), enableSplitStereo );
|
||||
// DA: Uses split stereo track and then drag pan sliders for split-stereo-to-mono
|
||||
#ifndef EXPERIMENTAL_DA
|
||||
POPUP_MENU_ITEM( "SplitToMono", OnSplitStereoMonoID, XO("Split Stereo to Mo&no"), OnSplitStereoMono)
|
||||
AppendItem( "SplitToMono", OnSplitStereoMonoID, XO("Split Stereo to Mo&no"), POPUP_MENU_FN( OnSplitStereoMono ), enableSplitStereo );
|
||||
#endif
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Format" )
|
||||
BeginSection( "Format" );
|
||||
POPUP_MENU_SUB_MENU( "Format", FormatMenuTable, mpData )
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Rate" )
|
||||
BeginSection( "Rate" );
|
||||
POPUP_MENU_SUB_MENU( "Rate", RateMenuTable, mpData )
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
END_POPUP_MENU()
|
||||
|
||||
|
||||
|
@ -266,46 +266,45 @@ PopupMenuTable &WaveformVRulerMenuTable::Instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WaveformVRulerMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
WaveTrackVRulerMenuTable::InitMenu(pMenu);
|
||||
|
||||
// DB setting is already on track drop down.
|
||||
WaveTrack *const wt = mpData->pTrack;
|
||||
const int id =
|
||||
OnFirstWaveformScaleID + (int)(wt->GetWaveformSettings().scaleType);
|
||||
pMenu->Check(id, true);
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveformVRulerMenuTable)
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Scales" )
|
||||
BeginSection( "Scales" );
|
||||
{
|
||||
const auto & names = WaveformSettings::GetScaleNames();
|
||||
for (int ii = 0, nn = names.size(); ii < nn; ++ii) {
|
||||
POPUP_MENU_RADIO_ITEM( names[ii].Internal(),
|
||||
AppendRadioItem( names[ii].Internal(),
|
||||
OnFirstWaveformScaleID + ii, names[ii].Msgid(),
|
||||
OnWaveformScaleType);
|
||||
POPUP_MENU_FN( OnWaveformScaleType ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
const auto pData =
|
||||
static_cast< WaveformVRulerMenuTable& >( handler ).mpData;
|
||||
WaveTrack *const wt = pData->pTrack;
|
||||
if ( id ==
|
||||
OnFirstWaveformScaleID +
|
||||
(int)(wt->GetWaveformSettings().scaleType) )
|
||||
menu.Check(id, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Zoom" )
|
||||
BEGIN_POPUP_MENU_SECTION( "Basic" )
|
||||
POPUP_MENU_ITEM( "Reset", OnZoomFitVerticalID, XO("Zoom Reset\tShift-Right-Click"), OnZoomReset)
|
||||
POPUP_MENU_ITEM( "TimesHalf", OnZoomDiv2ID, XO("Zoom x1/2"), OnZoomDiv2Vertical)
|
||||
POPUP_MENU_ITEM( "TimesTwo", OnZoomTimes2ID, XO("Zoom x2"), OnZoomTimes2Vertical)
|
||||
BeginSection( "Zoom" );
|
||||
BeginSection( "Basic" );
|
||||
AppendItem( "Reset", OnZoomFitVerticalID, XO("Zoom Reset\tShift-Right-Click"), POPUP_MENU_FN( OnZoomReset ) );
|
||||
AppendItem( "TimesHalf", OnZoomDiv2ID, XO("Zoom x1/2"), POPUP_MENU_FN( OnZoomDiv2Vertical ) );
|
||||
AppendItem( "TimesTwo", OnZoomTimes2ID, XO("Zoom x2"), POPUP_MENU_FN( OnZoomTimes2Vertical ) );
|
||||
|
||||
#ifdef EXPERIMENTAL_HALF_WAVE
|
||||
POPUP_MENU_ITEM( "HalfWave", OnZoomHalfWaveID, XO("Half Wave"), OnZoomHalfWave)
|
||||
AppendItem( "HalfWave", OnZoomHalfWaveID, XO("Half Wave"), POPUP_MENU_FN( OnZoomHalfWave ) );
|
||||
#endif
|
||||
END_POPUP_MENU_SECTION()
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "InOut" )
|
||||
POPUP_MENU_ITEM( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"), OnZoomInVertical)
|
||||
POPUP_MENU_ITEM( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"), OnZoomOutVertical)
|
||||
END_POPUP_MENU_SECTION()
|
||||
END_POPUP_MENU_SECTION()
|
||||
BeginSection( "InOut" );
|
||||
AppendItem( "In", OnZoomInVerticalID, XO("Zoom In\tLeft-Click/Left-Drag"), POPUP_MENU_FN( OnZoomInVertical ) );
|
||||
AppendItem( "Out", OnZoomOutVerticalID, XO("Zoom Out\tShift-Left-Click"), POPUP_MENU_FN( OnZoomOutVertical ) );
|
||||
EndSection();
|
||||
EndSection();
|
||||
|
||||
END_POPUP_MENU()
|
||||
|
||||
|
@ -85,8 +85,6 @@ public:
|
||||
static PopupMenuTable &Instance();
|
||||
|
||||
private:
|
||||
virtual void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void OnWaveformScaleType(wxCommandEvent &evt);
|
||||
};
|
||||
|
||||
|
@ -54,17 +54,6 @@ private:
|
||||
mpData = static_cast<CommonTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void InitMenu(wxMenu *pMenu) override
|
||||
{
|
||||
TimeTrack *const pTrack = static_cast<TimeTrack*>(mpData->pTrack);
|
||||
|
||||
pMenu->Check(OnTimeTrackLogIntID, pTrack->GetInterpolateLog());
|
||||
|
||||
auto isLog = pTrack->GetDisplayLog();
|
||||
pMenu->Check(OnTimeTrackLinID, !isLog);
|
||||
pMenu->Check(OnTimeTrackLogID, isLog);
|
||||
}
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = nullptr;
|
||||
@ -162,15 +151,34 @@ void TimeTrackMenuTable::OnTimeTrackLogInt(wxCommandEvent & /*event*/)
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(TimeTrackMenuTable)
|
||||
BEGIN_POPUP_MENU_SECTION( "Scales" )
|
||||
POPUP_MENU_RADIO_ITEM( "Linear", OnTimeTrackLinID, XO("&Linear scale"), OnTimeTrackLin)
|
||||
POPUP_MENU_RADIO_ITEM( "Log", OnTimeTrackLogID, XO("L&ogarithmic scale"), OnTimeTrackLog)
|
||||
END_POPUP_MENU_SECTION()
|
||||
static const auto findTrack = []( PopupMenuHandler &handler ){
|
||||
return static_cast<TimeTrack*>(
|
||||
static_cast<TimeTrackMenuTable&>( handler ).mpData->pTrack );
|
||||
};
|
||||
|
||||
BeginSection( "Scales" );
|
||||
AppendRadioItem( "Linear", OnTimeTrackLinID, XO("&Linear scale"),
|
||||
POPUP_MENU_FN( OnTimeTrackLin ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
menu.Check( id, !findTrack(handler)->GetDisplayLog() );
|
||||
} );
|
||||
AppendRadioItem( "Log", OnTimeTrackLogID, XO("L&ogarithmic scale"),
|
||||
POPUP_MENU_FN( OnTimeTrackLog ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
menu.Check( id, findTrack(handler)->GetDisplayLog() );
|
||||
} );
|
||||
EndSection();
|
||||
|
||||
BeginSection( "Other" );
|
||||
AppendItem( "Range", OnSetTimeTrackRangeID, XO("&Range..."),
|
||||
POPUP_MENU_FN( OnSetTimeTrackRange ) );
|
||||
AppendCheckItem( "LogInterp", OnTimeTrackLogIntID,
|
||||
XO("Logarithmic &Interpolation"), POPUP_MENU_FN( OnTimeTrackLogInt),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
menu.Check( id, findTrack(handler)->GetInterpolateLog() );
|
||||
} );
|
||||
EndSection();
|
||||
|
||||
BEGIN_POPUP_MENU_SECTION( "Other" )
|
||||
POPUP_MENU_ITEM( "Range", OnSetTimeTrackRangeID, XO("&Range..."), OnSetTimeTrackRange)
|
||||
POPUP_MENU_CHECK_ITEM( "LogInterp", OnTimeTrackLogIntID, XO("Logarithmic &Interpolation"), OnTimeTrackLogInt)
|
||||
END_POPUP_MENU_SECTION()
|
||||
END_POPUP_MENU()
|
||||
|
||||
PopupMenuTable *TimeTrackControls::GetMenuExtension(Track *)
|
||||
|
@ -93,7 +93,6 @@ private:
|
||||
void OnMoveTrack(wxCommandEvent &event);
|
||||
|
||||
void InitUserData(void *pUserData) override;
|
||||
void InitMenu(wxMenu *pMenu) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
@ -114,24 +113,22 @@ void TrackMenuTable::InitUserData(void *pUserData)
|
||||
mpData = static_cast<CommonTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
void TrackMenuTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
Track *const pTrack = mpData->pTrack;
|
||||
|
||||
const auto &tracks = TrackList::Get( mpData->project );
|
||||
|
||||
pMenu->Enable(OnMoveUpID, tracks.CanMoveUp(pTrack));
|
||||
pMenu->Enable(OnMoveDownID, tracks.CanMoveDown(pTrack));
|
||||
pMenu->Enable(OnMoveTopID, tracks.CanMoveUp(pTrack));
|
||||
pMenu->Enable(OnMoveBottomID, tracks.CanMoveDown(pTrack));
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(TrackMenuTable)
|
||||
BEGIN_POPUP_MENU_SECTION( "Basic" )
|
||||
POPUP_MENU_ITEM( "Name", OnSetNameID, XO("&Name..."), OnSetName)
|
||||
END_POPUP_MENU_SECTION()
|
||||
BEGIN_POPUP_MENU_SECTION( "Move" )
|
||||
POPUP_MENU_ITEM( "Up",
|
||||
static const auto enableIfCanMove = [](bool up){ return
|
||||
[up]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto pData = static_cast<TrackMenuTable&>( handler ).mpData;
|
||||
const auto &tracks = TrackList::Get( pData->project );
|
||||
Track *const pTrack = pData->pTrack;
|
||||
menu.Enable( id,
|
||||
up ? tracks.CanMoveUp(pTrack) : tracks.CanMoveDown(pTrack) );
|
||||
};
|
||||
};
|
||||
|
||||
BeginSection( "Basic" );
|
||||
AppendItem( "Name", OnSetNameID, XO("&Name..."), POPUP_MENU_FN( OnSetName ) );
|
||||
EndSection();
|
||||
BeginSection( "Move" );
|
||||
AppendItem( "Up",
|
||||
// It is not correct to use NormalizedKeyString::Display here --
|
||||
// wxWidgets will apply its equivalent to the key names passed to menu
|
||||
// functions.
|
||||
@ -143,8 +140,8 @@ BEGIN_POPUP_MENU(TrackMenuTable)
|
||||
GetKeyFromName(wxT("TrackMoveUp")).GET() ),
|
||||
wxT("\t")
|
||||
),
|
||||
OnMoveTrack)
|
||||
POPUP_MENU_ITEM( "Down",
|
||||
POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
|
||||
AppendItem( "Down",
|
||||
OnMoveDownID,
|
||||
XO("Move Track &Down").Join(
|
||||
Verbatim(
|
||||
@ -153,8 +150,8 @@ BEGIN_POPUP_MENU(TrackMenuTable)
|
||||
GetKeyFromName(wxT("TrackMoveDown")).GET() ),
|
||||
wxT("\t")
|
||||
),
|
||||
OnMoveTrack)
|
||||
POPUP_MENU_ITEM( "Top",
|
||||
POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
|
||||
AppendItem( "Top",
|
||||
OnMoveTopID,
|
||||
XO("Move Track to &Top").Join(
|
||||
Verbatim(
|
||||
@ -163,8 +160,8 @@ BEGIN_POPUP_MENU(TrackMenuTable)
|
||||
GetKeyFromName(wxT("TrackMoveTop")).GET() ),
|
||||
wxT("\t")
|
||||
),
|
||||
OnMoveTrack)
|
||||
POPUP_MENU_ITEM( "Bottom",
|
||||
POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(true) );
|
||||
AppendItem( "Bottom",
|
||||
OnMoveBottomID,
|
||||
XO("Move Track to &Bottom").Join(
|
||||
Verbatim(
|
||||
@ -173,8 +170,8 @@ BEGIN_POPUP_MENU(TrackMenuTable)
|
||||
GetKeyFromName(wxT("TrackMoveBottom")).GET() ),
|
||||
wxT("\t")
|
||||
),
|
||||
OnMoveTrack)
|
||||
END_POPUP_MENU_SECTION()
|
||||
POPUP_MENU_FN( OnMoveTrack ), enableIfCanMove(false) );
|
||||
EndSection();
|
||||
END_POPUP_MENU()
|
||||
|
||||
|
||||
|
@ -80,7 +80,6 @@ void PopupMenuBuilder::DoBeginGroup( Registry::GroupItem &item, const Path &path
|
||||
void PopupMenuBuilder::DoEndGroup( Registry::GroupItem &item, const Path &path )
|
||||
{
|
||||
if ( auto pItem = dynamic_cast<PopupSubMenu*>(&item) ) {
|
||||
pItem->table.InitMenu( mMenu );
|
||||
if ( !pItem->caption.empty() ) {
|
||||
auto subMenu = std::move( mMenus.back() );
|
||||
mMenus.pop_back();
|
||||
@ -92,35 +91,37 @@ void PopupMenuBuilder::DoEndGroup( Registry::GroupItem &item, const Path &path )
|
||||
|
||||
void PopupMenuBuilder::DoVisit( Registry::SingleItem &item, const Path &path )
|
||||
{
|
||||
auto connect = [this]( const PopupMenuTable::Entry *pEntry ) {
|
||||
mMenu->pParent->Bind
|
||||
(wxEVT_COMMAND_MENU_SELECTED,
|
||||
pEntry->func, mMenu->tables.back(), pEntry->id);
|
||||
};
|
||||
|
||||
auto pEntry = static_cast<PopupMenuTableEntry*>( &item );
|
||||
switch (pEntry->type) {
|
||||
case PopupMenuTable::Entry::Item:
|
||||
{
|
||||
mMenu->Append(pEntry->id, pEntry->caption.Translation());
|
||||
connect( pEntry );
|
||||
break;
|
||||
}
|
||||
case PopupMenuTable::Entry::RadioItem:
|
||||
{
|
||||
mMenu->AppendRadioItem(pEntry->id, pEntry->caption.Translation());
|
||||
connect( pEntry );
|
||||
break;
|
||||
}
|
||||
case PopupMenuTable::Entry::CheckItem:
|
||||
{
|
||||
mMenu->AppendCheckItem(pEntry->id, pEntry->caption.Translation());
|
||||
connect( pEntry );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
wxASSERT( false );
|
||||
break;
|
||||
}
|
||||
|
||||
// This call necessary for externally registered items, else harmlessly
|
||||
// redundant
|
||||
pEntry->handler.InitUserData( mpUserData );
|
||||
|
||||
if ( pEntry->init )
|
||||
pEntry->init( pEntry->handler, *mMenu, pEntry->id );
|
||||
|
||||
mMenu->pParent->Bind(
|
||||
wxEVT_COMMAND_MENU_SELECTED, pEntry->func, &pEntry->handler, pEntry->id);
|
||||
}
|
||||
|
||||
void PopupMenuBuilder::DoSeparator()
|
||||
@ -145,6 +146,29 @@ void PopupMenuTable::ExtendMenu( wxMenu &menu, PopupMenuTable &table )
|
||||
Registry::Visit( visitor, table.Get( theMenu.pUserData ).get() );
|
||||
}
|
||||
|
||||
void PopupMenuTable::Append(
|
||||
const Identifier &stringId, PopupMenuTableEntry::Type type, int id,
|
||||
const TranslatableString &string, wxCommandEventFunction memFn,
|
||||
const PopupMenuTableEntry::InitFunction &init )
|
||||
{
|
||||
mStack.back()->items.push_back( std::make_unique<Entry>(
|
||||
stringId, type, id, string, memFn, *this, init
|
||||
) );
|
||||
}
|
||||
|
||||
void PopupMenuTable::BeginSection( const Identifier &name )
|
||||
{
|
||||
auto uSection = std::make_unique< PopupMenuSection >( name );
|
||||
auto section = uSection.get();
|
||||
mStack.back()->items.push_back( std::move( uSection ) );
|
||||
mStack.push_back( section );
|
||||
}
|
||||
|
||||
void PopupMenuTable::EndSection()
|
||||
{
|
||||
mStack.pop_back();
|
||||
}
|
||||
|
||||
namespace{
|
||||
void PopupMenu::DisconnectTable(PopupMenuTable *pTable)
|
||||
{
|
||||
@ -160,7 +184,8 @@ void PopupMenu::DisconnectTable(PopupMenuTable *pTable)
|
||||
{
|
||||
auto pEntry = static_cast<PopupMenuTableEntry*>( &item );
|
||||
mMenu.pParent->Unbind( wxEVT_COMMAND_MENU_SELECTED,
|
||||
pEntry->func, &mTable, pEntry->id );
|
||||
pEntry->func, &pEntry->handler, pEntry->id );
|
||||
pEntry->handler.DestroyMenu();
|
||||
}
|
||||
|
||||
PopupMenuTable &mTable;
|
||||
@ -169,8 +194,6 @@ void PopupMenu::DisconnectTable(PopupMenuTable *pTable)
|
||||
|
||||
PopupMenuDestroyer visitor{ *pTable, *this };
|
||||
Registry::Visit( visitor, pTable->Get( nullptr ).get() );
|
||||
|
||||
pTable->DestroyMenu();
|
||||
}
|
||||
|
||||
void PopupMenu::Disconnect()
|
||||
@ -180,10 +203,6 @@ void PopupMenu::Disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
void PopupMenuTable::InitMenu(wxMenu *)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<wxMenu> PopupMenuTable::BuildMenu
|
||||
( wxEvtHandler *pParent, PopupMenuTable *pTable, void *pUserData )
|
||||
|
@ -20,6 +20,7 @@ tables, and automatically attaches and detaches the event handlers.
|
||||
|
||||
class wxCommandEvent;
|
||||
class wxString;
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <wx/menu.h> // to inherit wxMenu
|
||||
#include "../MemoryX.h"
|
||||
@ -27,26 +28,33 @@ class wxString;
|
||||
#include "../Internat.h"
|
||||
#include "../commands/CommandManager.h"
|
||||
|
||||
class PopupMenuHandler;
|
||||
class PopupMenuTable;
|
||||
|
||||
struct PopupMenuTableEntry : Registry::SingleItem
|
||||
{
|
||||
enum Type { Item, RadioItem, CheckItem };
|
||||
using InitFunction =
|
||||
std::function< void( PopupMenuHandler &handler, wxMenu &menu, int id ) >;
|
||||
|
||||
Type type;
|
||||
int id;
|
||||
TranslatableString caption;
|
||||
wxCommandEventFunction func;
|
||||
PopupMenuTable *subTable;
|
||||
PopupMenuHandler &handler;
|
||||
InitFunction init;
|
||||
|
||||
PopupMenuTableEntry( const Identifier &stringId,
|
||||
Type type_, int id_, const TranslatableString &caption_,
|
||||
wxCommandEventFunction func_)
|
||||
wxCommandEventFunction func_, PopupMenuHandler &handler_,
|
||||
InitFunction init_ )
|
||||
: SingleItem{ stringId }
|
||||
, type(type_)
|
||||
, id(id_)
|
||||
, caption(caption_)
|
||||
, func(func_)
|
||||
, handler( handler_ )
|
||||
, init( init_ )
|
||||
{}
|
||||
|
||||
~PopupMenuTableEntry() override;
|
||||
@ -70,7 +78,24 @@ struct PopupMenuSection
|
||||
using ConcreteGroupItem< false >::ConcreteGroupItem;
|
||||
};
|
||||
|
||||
class PopupMenuTable : public wxEvtHandler
|
||||
class PopupMenuHandler : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
PopupMenuHandler() = default;
|
||||
PopupMenuHandler( const PopupMenuHandler& ) = delete;
|
||||
PopupMenuHandler& operator=( const PopupMenuHandler& ) = delete;
|
||||
|
||||
// Called before the menu items are appended.
|
||||
// Store context data, if needed.
|
||||
// May be called more than once before the menu opens.
|
||||
virtual void InitUserData(void *pUserData) = 0;
|
||||
|
||||
// Called when menu is destroyed.
|
||||
// May be called more than once.
|
||||
virtual void DestroyMenu() = 0;
|
||||
};
|
||||
|
||||
class PopupMenuTable : public PopupMenuHandler
|
||||
{
|
||||
public:
|
||||
using Entry = PopupMenuTableEntry;
|
||||
@ -81,18 +106,6 @@ public:
|
||||
, mCaption{ caption }
|
||||
{}
|
||||
|
||||
// Called before the menu items are appended.
|
||||
// Store user data, if needed.
|
||||
virtual void InitUserData(void *pUserData) = 0;
|
||||
|
||||
// Called when the menu is about to pop up.
|
||||
// Your chance to enable and disable items.
|
||||
// Default implementation does nothing.
|
||||
virtual void InitMenu(wxMenu *pMenu);
|
||||
|
||||
// Called when menu is destroyed.
|
||||
virtual void DestroyMenu() = 0;
|
||||
|
||||
// Optional pUserData gets passed to the InitUserData routines of tables.
|
||||
// No memory management responsibility is assumed by this function.
|
||||
static std::unique_ptr<wxMenu> BuildMenu
|
||||
@ -115,6 +128,34 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void Populate() = 0;
|
||||
|
||||
// To be used in implementations of Populate():
|
||||
void Append(
|
||||
const Identifier &stringId, PopupMenuTableEntry::Type type, int id,
|
||||
const TranslatableString &string, wxCommandEventFunction memFn,
|
||||
// This callback might check or disable a menu item:
|
||||
const PopupMenuTableEntry::InitFunction &init );
|
||||
|
||||
void AppendItem( const Identifier &stringId, int id,
|
||||
const TranslatableString &string, wxCommandEventFunction memFn,
|
||||
// This callback might check or disable a menu item:
|
||||
const PopupMenuTableEntry::InitFunction &init = {} )
|
||||
{ Append( stringId, PopupMenuTableEntry::Item, id, string, memFn, init ); }
|
||||
|
||||
void AppendRadioItem( const Identifier &stringId, int id,
|
||||
const TranslatableString &string, wxCommandEventFunction memFn,
|
||||
// This callback might check or disable a menu item:
|
||||
const PopupMenuTableEntry::InitFunction &init = {} )
|
||||
{ Append( stringId, PopupMenuTableEntry::RadioItem, id, string, memFn, init ); }
|
||||
|
||||
void AppendCheckItem( const Identifier &stringId, int id,
|
||||
const TranslatableString &string, wxCommandEventFunction memFn,
|
||||
const PopupMenuTableEntry::InitFunction &init = {} )
|
||||
{ Append( stringId, PopupMenuTableEntry::CheckItem, id, string, memFn, init ); }
|
||||
|
||||
void BeginSection( const Identifier &name );
|
||||
void EndSection();
|
||||
|
||||
void Clear() { mTop.reset(); }
|
||||
|
||||
std::shared_ptr< Registry::GroupItem > mTop;
|
||||
@ -133,7 +174,6 @@ which inherits from PopupMenuTable,
|
||||
|
||||
DECLARE_POPUP_MENU(MyTable);
|
||||
virtual void InitUserData(void *pUserData);
|
||||
virtual void InitMenu(wxMenu *pMenu);
|
||||
virtual void DestroyMenu();
|
||||
|
||||
Then in MyTable.cpp,
|
||||
@ -144,11 +184,6 @@ void MyTable::InitUserData(void *pUserData)
|
||||
auto pData = static_cast<MyData*>(pUserData);
|
||||
}
|
||||
|
||||
void MyTable::InitMenu(wxMenu *pMenu)
|
||||
{
|
||||
// enable or disable menu items
|
||||
}
|
||||
|
||||
void MyTable::DestroyMenu()
|
||||
{
|
||||
// Do cleanup
|
||||
@ -156,9 +191,17 @@ void MyTable::DestroyMenu()
|
||||
|
||||
BEGIN_POPUP_MENU(MyTable)
|
||||
// This is inside a function and can contain arbitrary code. But usually
|
||||
// you only need a sequence of macro calls:
|
||||
// you only need a sequence of calls:
|
||||
|
||||
POPUP_MENU_ITEM("Cut", OnCutSelectedTextID, XO("Cu&t"), OnCutSelectedText)
|
||||
AppendItem("Cut",
|
||||
OnCutSelectedTextID, XO("Cu&t"), POPUP_MENU_FN( OnCutSelectedText ),
|
||||
// optional argument:
|
||||
[](PopupMenuHandler &handler, wxMenu &menu, int id)
|
||||
{
|
||||
auto data = static_cast<MyTable&>( handler ).pData;
|
||||
// maybe enable or disable the menu item
|
||||
}
|
||||
);
|
||||
// etc.
|
||||
|
||||
END_POPUP_MENU()
|
||||
@ -192,46 +235,12 @@ void HandlerClass::Populate() { \
|
||||
mStack.clear(); \
|
||||
mStack.push_back( mTop.get() );
|
||||
|
||||
#define POPUP_MENU_APPEND(stringId, type, id, string, memFn) \
|
||||
mStack.back()->items.push_back( std::make_unique<Entry>( \
|
||||
Identifier{ stringId }, \
|
||||
type, \
|
||||
id, \
|
||||
string, \
|
||||
memFn \
|
||||
) );
|
||||
#define POPUP_MENU_FN( memFn ) ( (wxCommandEventFunction) (&My::memFn) )
|
||||
|
||||
#define POPUP_MENU_APPEND_ITEM(stringId, type, id, string, memFn) \
|
||||
POPUP_MENU_APPEND( stringId, \
|
||||
type, \
|
||||
id, \
|
||||
string, \
|
||||
(wxCommandEventFunction) (&My::memFn) )
|
||||
|
||||
#define POPUP_MENU_ITEM(stringId, id, string, memFn) \
|
||||
POPUP_MENU_APPEND_ITEM(stringId, Entry::Item, id, string, memFn);
|
||||
|
||||
#define POPUP_MENU_RADIO_ITEM(stringId, id, string, memFn) \
|
||||
POPUP_MENU_APPEND_ITEM(stringId, Entry::RadioItem, id, string, memFn);
|
||||
|
||||
#define POPUP_MENU_CHECK_ITEM(stringId, id, string, memFn) \
|
||||
POPUP_MENU_APPEND_ITEM(stringId, Entry::CheckItem, id, string, memFn);
|
||||
|
||||
// classname names a class that derives from MenuTable and defines Instance()
|
||||
#define POPUP_MENU_SUB_MENU(stringId, classname, pUserData ) \
|
||||
mStack.back()->items.push_back( \
|
||||
Registry::Shared( classname::Instance().Get( pUserData ) ) );
|
||||
|
||||
#define BEGIN_POPUP_MENU_SECTION( name ) \
|
||||
{ auto uSection = std::make_unique< PopupMenuSection >( \
|
||||
Identifier{ name } ); \
|
||||
auto section = uSection.get(); \
|
||||
mStack.back()->items.push_back( std::move( uSection ) ); \
|
||||
mStack.push_back( section ); \
|
||||
}
|
||||
|
||||
#define END_POPUP_MENU_SECTION() mStack.pop_back();
|
||||
|
||||
// ends function
|
||||
#define END_POPUP_MENU() }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user