mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-23 15:50:05 +02:00
Register Wave Color, Spectrogram Settings popup menu items...
... and so WaveTrackControls knows how to make multi views or switch among single views, and can change track contents such as display format and rate, but knows nothing about view-specific display details
This commit is contained in:
commit
06d4c0bdd7
@ -665,3 +665,144 @@ static const WaveTrackSubViews::RegisteredFactory key{
|
||||
return std::make_shared< SpectrumView >( view );
|
||||
}
|
||||
};
|
||||
|
||||
// The following attaches the spectrogram settings item to the wave track popup
|
||||
// menu. It is appropriate only to spectrum view and so is kept in this
|
||||
// source file with the rest of the spectrum view implementation.
|
||||
#include "WaveTrackControls.h"
|
||||
#include "../../../../AudioIOBase.h"
|
||||
#include "../../../../Menus.h"
|
||||
#include "../../../../ProjectHistory.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
#include "../../../../prefs/PrefsDialog.h"
|
||||
#include "../../../../prefs/SpectrumPrefs.h"
|
||||
#include "../../../../widgets/AudacityMessageBox.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
|
||||
namespace {
|
||||
struct SpectrogramSettingsHandler : PopupMenuHandler {
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
static SpectrogramSettingsHandler &Instance()
|
||||
{
|
||||
static SpectrogramSettingsHandler instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void OnSpectrogramSettings(wxCommandEvent &);
|
||||
|
||||
void InitUserData(void *pUserData) override
|
||||
{
|
||||
mpData = static_cast< PlayableTrackControls::InitMenuData* >(pUserData);
|
||||
}
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void SpectrogramSettingsHandler::OnSpectrogramSettings(wxCommandEvent &)
|
||||
{
|
||||
class ViewSettingsDialog final : public PrefsDialog
|
||||
{
|
||||
public:
|
||||
ViewSettingsDialog(wxWindow *parent, AudacityProject &project,
|
||||
const TranslatableString &title, PrefsDialog::Factories &factories,
|
||||
int page)
|
||||
: PrefsDialog(parent, &project, title, factories)
|
||||
, mPage(page)
|
||||
{
|
||||
}
|
||||
|
||||
long GetPreferredPage() override
|
||||
{
|
||||
return mPage;
|
||||
}
|
||||
|
||||
void SavePreferredPage() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const int mPage;
|
||||
};
|
||||
|
||||
auto gAudioIO = AudioIOBase::Get();
|
||||
if (gAudioIO->IsBusy()){
|
||||
AudacityMessageBox(
|
||||
XO(
|
||||
"To change Spectrogram Settings, stop any\n playing or recording first."),
|
||||
XO("Stop the Audio First"),
|
||||
wxOK | wxICON_EXCLAMATION | wxCENTRE);
|
||||
return;
|
||||
}
|
||||
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
PrefsDialog::Factories factories;
|
||||
// factories.push_back(WaveformPrefsFactory( pTrack ));
|
||||
factories.push_back(SpectrumPrefsFactory( pTrack ));
|
||||
const int page =
|
||||
// (pTrack->GetDisplay() == WaveTrackViewConstants::Spectrum) ? 1 :
|
||||
0;
|
||||
|
||||
auto title = XO("%s:").Format( pTrack->GetName() );
|
||||
ViewSettingsDialog dialog(
|
||||
mpData->pParent, mpData->project, title, factories, page);
|
||||
|
||||
if (0 != dialog.ShowModal()) {
|
||||
// Redraw
|
||||
AudacityProject *const project = &mpData->project;
|
||||
ProjectHistory::Get( *project ).ModifyState(true);
|
||||
//Bug 1725 Toolbar was left greyed out.
|
||||
//This solution is overkill, but does fix the problem and is what the
|
||||
//prefs dialog normally does.
|
||||
MenuCreator::RebuildAllMenuBars();
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenuTable::AttachedItem sAttachment{
|
||||
GetWaveTrackMenuTable(),
|
||||
{ "SubViews/Extra" },
|
||||
std::make_unique<PopupMenuSection>( "SpectrogramSettings",
|
||||
// Conditionally add menu item for settings, if showing spectrum
|
||||
PopupMenuTable::Computed< WaveTrackPopupMenuTable >(
|
||||
[]( WaveTrackPopupMenuTable &table ) -> Registry::BaseItemPtr {
|
||||
using Entry = PopupMenuTable::Entry;
|
||||
static const int OnSpectrogramSettingsID =
|
||||
GetWaveTrackMenuTable().ReserveId();
|
||||
|
||||
const auto pTrack = &table.FindWaveTrack();
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
const auto displays = view.GetDisplays();
|
||||
bool hasSpectrum = (displays.end() != std::find(
|
||||
displays.begin(), displays.end(),
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
|
||||
) );
|
||||
if( hasSpectrum )
|
||||
// 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.)
|
||||
return std::make_unique<Entry>( "SpectrogramSettings",
|
||||
Entry::Item,
|
||||
OnSpectrogramSettingsID,
|
||||
XO("S&pectrogram Settings..."),
|
||||
(wxCommandEventFunction)
|
||||
(&SpectrogramSettingsHandler::OnSpectrogramSettings),
|
||||
SpectrogramSettingsHandler::Instance(),
|
||||
[]( 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());
|
||||
} );
|
||||
else
|
||||
return nullptr;
|
||||
} ) )
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "WaveTrackSliderHandles.h"
|
||||
|
||||
#include "WaveTrackView.h"
|
||||
#include "WaveTrackViewConstants.h"
|
||||
#include "../../../../AudioIOBase.h"
|
||||
#include "../../../../CellularPanel.h"
|
||||
#include "../../../../Menus.h"
|
||||
@ -30,13 +31,10 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../../../TrackPanelAx.h"
|
||||
#include "../../../../TrackPanelMouseEvent.h"
|
||||
#include "../../../../WaveTrack.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../effects/RealtimeEffectManager.h"
|
||||
#include "../../../../ondemand/ODManager.h"
|
||||
#include "../../../../prefs/PrefsDialog.h"
|
||||
#include "../../../../prefs/SpectrumPrefs.h"
|
||||
#include "../../../../prefs/ThemePrefs.h"
|
||||
#include "../../../../prefs/WaveformPrefs.h"
|
||||
#include "../../../../widgets/AudacityMessageBox.h"
|
||||
|
||||
#include <wx/combobox.h>
|
||||
@ -87,6 +85,11 @@ std::vector<UIHandlePtr> WaveTrackControls::HitTest
|
||||
return PlayableTrackControls::HitTest(st, pProject);
|
||||
}
|
||||
|
||||
WaveTrack &WaveTrackPopupMenuTable::FindWaveTrack() const
|
||||
{
|
||||
return *static_cast< WaveTrack* >( mpData->pTrack );
|
||||
};
|
||||
|
||||
enum {
|
||||
reserveDisplays = 100,
|
||||
|
||||
@ -112,23 +115,20 @@ enum {
|
||||
|
||||
OnSetDisplayId, lastDisplayId = (OnSetDisplayId + reserveDisplays - 1),
|
||||
|
||||
OnSpectrogramSettingsID,
|
||||
|
||||
OnChannelLeftID,
|
||||
OnChannelRightID,
|
||||
OnChannelMonoID,
|
||||
|
||||
OnMergeStereoID,
|
||||
OnInstrument1ID,
|
||||
OnInstrument2ID,
|
||||
OnInstrument3ID,
|
||||
OnInstrument4ID,
|
||||
|
||||
OnSwapChannelsID,
|
||||
OnSplitStereoID,
|
||||
OnSplitStereoMonoID,
|
||||
|
||||
ChannelMenuID,
|
||||
|
||||
// Range of ids for registered items -- keep this last!
|
||||
FirstAttachedItemId,
|
||||
};
|
||||
|
||||
|
||||
@ -152,94 +152,6 @@ PopupMenuTableEntry::InitFunction initFn( const ValueFinder &findValue )
|
||||
};
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
struct WaveColorMenuTable : PopupMenuTable
|
||||
{
|
||||
WaveColorMenuTable()
|
||||
: PopupMenuTable( "WaveColor", XO("&Wave Color") )
|
||||
{}
|
||||
DECLARE_POPUP_MENU(WaveColorMenuTable);
|
||||
|
||||
static WaveColorMenuTable &Instance();
|
||||
|
||||
void InitUserData(void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = NULL;
|
||||
}
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
static int IdOfWaveColor(int WaveColor);
|
||||
void OnWaveColorChange(wxCommandEvent & event);
|
||||
};
|
||||
|
||||
WaveColorMenuTable &WaveColorMenuTable::Instance()
|
||||
{
|
||||
static WaveColorMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WaveColorMenuTable::InitUserData(void *pUserData)
|
||||
{
|
||||
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
const TranslatableString GetWaveColorStr(int colorIndex)
|
||||
{
|
||||
return XO("Instrument %i").Format( colorIndex+1 );
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveColorMenuTable)
|
||||
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.
|
||||
int WaveColorMenuTable::IdOfWaveColor(int WaveColor)
|
||||
{ return OnInstrument1ID + WaveColor;}
|
||||
|
||||
/// Handles the selection from the WaveColor submenu of the
|
||||
/// track menu.
|
||||
void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnInstrument1ID && id <= OnInstrument4ID);
|
||||
const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
int newWaveColor = id - OnInstrument1ID;
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
|
||||
for (auto channel : TrackList::Channels(pTrack))
|
||||
channel->SetWaveColorIndex(newWaveColor);
|
||||
|
||||
ProjectHistory::Get( *project )
|
||||
.PushState(XO("Changed '%s' to %s")
|
||||
.Format( pTrack->GetName(), GetWaveColorStr(newWaveColor) ),
|
||||
XO("WaveColor Change"));
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
@ -548,30 +460,33 @@ void RateMenuTable::OnRateOther(wxCommandEvent &)
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
static const auto MenuPathStart = wxT("WaveTrackMenu");
|
||||
|
||||
//=============================================================================
|
||||
// Class defining common command handlers for mono and stereo tracks
|
||||
struct WaveTrackMenuTable : ComputedPopupMenuTable< WaveTrackMenuTable >
|
||||
struct WaveTrackMenuTable
|
||||
: ComputedPopupMenuTable< WaveTrackMenuTable, WaveTrackPopupMenuTable >
|
||||
{
|
||||
static WaveTrackMenuTable &Instance();
|
||||
|
||||
WaveTrackMenuTable()
|
||||
: ComputedPopupMenuTable< WaveTrackMenuTable >{ "WaveTrack" }
|
||||
{}
|
||||
: ComputedPopupMenuTable< WaveTrackMenuTable, WaveTrackPopupMenuTable >{
|
||||
MenuPathStart }
|
||||
{
|
||||
mNextId = FirstAttachedItemId;
|
||||
}
|
||||
|
||||
void InitUserData(void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = nullptr;
|
||||
//mpData = nullptr;
|
||||
}
|
||||
|
||||
DECLARE_POPUP_MENU(WaveTrackMenuTable);
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
void OnMultiView(wxCommandEvent & event);
|
||||
void OnSetDisplay(wxCommandEvent & event);
|
||||
void OnSpectrogramSettings(wxCommandEvent & event);
|
||||
|
||||
void OnChannelChange(wxCommandEvent & event);
|
||||
void OnMergeStereo(wxCommandEvent & event);
|
||||
@ -608,15 +523,11 @@ static std::vector<WaveTrackSubViewType> AllTypes()
|
||||
|
||||
BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
// Functions usable in callbacks to check and disable items
|
||||
static const auto findTrack =
|
||||
[]( PopupMenuHandler &handler ) -> WaveTrack & {
|
||||
return *static_cast< WaveTrack* >(
|
||||
static_cast< WaveTrackMenuTable& >( handler ).mpData->pTrack);
|
||||
};
|
||||
|
||||
static const auto isMono =
|
||||
[]( PopupMenuHandler &handler ) -> bool {
|
||||
return 1 == TrackList::Channels( &findTrack( handler ) ).size();
|
||||
auto &track =
|
||||
static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
|
||||
return 1 == TrackList::Channels( &track ).size();
|
||||
};
|
||||
|
||||
static const auto isUnsafe =
|
||||
@ -637,7 +548,8 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
POPUP_MENU_FN( OnMultiView ),
|
||||
table,
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto &track = findTrack( handler );
|
||||
auto &table = static_cast< WaveTrackMenuTable& >( handler );
|
||||
auto &track = table.FindWaveTrack();
|
||||
const auto &view = WaveTrackView::Get( track );
|
||||
menu.Check( id, view.GetMultiView() );
|
||||
} );
|
||||
@ -662,7 +574,9 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
(std::find( begin, allTypes.end(), type ) - begin);
|
||||
};
|
||||
|
||||
auto &track = findTrack( handler );
|
||||
auto &table = static_cast< WaveTrackMenuTable& >( handler );
|
||||
auto &track = table.FindWaveTrack();
|
||||
|
||||
const auto &view = WaveTrackView::Get( track );
|
||||
|
||||
const auto displays = view.GetDisplays();
|
||||
@ -680,7 +594,7 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
};
|
||||
};
|
||||
Append( [type, id]( My &table ) -> Registry::BaseItemPtr {
|
||||
const auto pTrack = &findTrack( table );
|
||||
const auto pTrack = &table.FindWaveTrack();
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
const auto itemType =
|
||||
view.GetMultiView() ? Entry::CheckItem : Entry::RadioItem;
|
||||
@ -691,54 +605,9 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
} );
|
||||
++id;
|
||||
}
|
||||
BeginSection( "Extra" );
|
||||
EndSection();
|
||||
EndSection();
|
||||
|
||||
// Conditionally add sub-menu for wave color, if showing waveform
|
||||
Append( []( My &table ) -> Registry::BaseItemPtr {
|
||||
const auto pTrack = &findTrack( table );
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
const auto displays = view.GetDisplays();
|
||||
bool hasWaveform = (displays.end() != std::find(
|
||||
displays.begin(), displays.end(),
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} }
|
||||
) );
|
||||
if( hasWaveform )
|
||||
return std::make_unique<PopupMenuSection>( "WaveColor",
|
||||
Registry::Shared( WaveColorMenuTable::Instance()
|
||||
.Get( table.mpData ) ) );
|
||||
else
|
||||
return nullptr;
|
||||
} );
|
||||
|
||||
// Conditionally add sub-menu for spectrogram settings, if showing spectrum
|
||||
Append( []( My &table ) -> Registry::BaseItemPtr {
|
||||
const auto pTrack = &findTrack( table );
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
const auto displays = view.GetDisplays();
|
||||
bool hasSpectrum = (displays.end() != std::find(
|
||||
displays.begin(), displays.end(),
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
|
||||
) );
|
||||
if( hasSpectrum )
|
||||
// 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.)
|
||||
return std::make_unique<PopupMenuSection>( "SpectrogramSettings",
|
||||
std::make_unique<Entry>( "SpectrogramSettings", Entry::Item,
|
||||
OnSpectrogramSettingsID,
|
||||
XO("S&pectrogram Settings..."),
|
||||
POPUP_MENU_FN( OnSpectrogramSettings ), table,
|
||||
[]( 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());
|
||||
} ) );
|
||||
else
|
||||
return nullptr;
|
||||
} );
|
||||
|
||||
BeginSection( "Channels" );
|
||||
// If these are enabled again, choose a hot key for Mono that does not conflict
|
||||
@ -772,7 +641,8 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
AudacityProject &project =
|
||||
static_cast< WaveTrackMenuTable& >( handler ).mpData->project;
|
||||
auto &tracks = TrackList::Get( project );
|
||||
auto &track = findTrack( handler );
|
||||
auto &table = static_cast< WaveTrackMenuTable& >( handler );
|
||||
auto &track = table.FindWaveTrack();
|
||||
auto next = * ++ tracks.Find(&track);
|
||||
canMakeStereo =
|
||||
(next &&
|
||||
@ -786,8 +656,10 @@ BEGIN_POPUP_MENU(WaveTrackMenuTable)
|
||||
AppendItem( "Swap", OnSwapChannelsID, XO("Swap Stereo &Channels"),
|
||||
POPUP_MENU_FN( OnSwapChannels ),
|
||||
[]( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto &track =
|
||||
static_cast< WaveTrackMenuTable& >( handler ).FindWaveTrack();
|
||||
bool isStereo =
|
||||
2 == TrackList::Channels( &findTrack( handler ) ).size();
|
||||
2 == TrackList::Channels( &track ).size();
|
||||
menu.Enable( id, isStereo && !isUnsafe( handler ) );
|
||||
}
|
||||
);
|
||||
@ -879,67 +751,6 @@ void WaveTrackMenuTable::OnSetDisplay(wxCommandEvent & event)
|
||||
}
|
||||
}
|
||||
|
||||
void WaveTrackMenuTable::OnSpectrogramSettings(wxCommandEvent &)
|
||||
{
|
||||
class ViewSettingsDialog final : public PrefsDialog
|
||||
{
|
||||
public:
|
||||
ViewSettingsDialog(wxWindow *parent, AudacityProject &project,
|
||||
const TranslatableString &title, PrefsDialog::Factories &factories,
|
||||
int page)
|
||||
: PrefsDialog(parent, &project, title, factories)
|
||||
, mPage(page)
|
||||
{
|
||||
}
|
||||
|
||||
long GetPreferredPage() override
|
||||
{
|
||||
return mPage;
|
||||
}
|
||||
|
||||
void SavePreferredPage() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const int mPage;
|
||||
};
|
||||
|
||||
auto gAudioIO = AudioIOBase::Get();
|
||||
if (gAudioIO->IsBusy()){
|
||||
AudacityMessageBox(
|
||||
XO(
|
||||
"To change Spectrogram Settings, stop any\n playing or recording first."),
|
||||
XO("Stop the Audio First"),
|
||||
wxOK | wxICON_EXCLAMATION | wxCENTRE);
|
||||
return;
|
||||
}
|
||||
|
||||
WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
PrefsDialog::Factories factories;
|
||||
// factories.push_back(WaveformPrefsFactory( pTrack ));
|
||||
factories.push_back(SpectrumPrefsFactory( pTrack ));
|
||||
const int page =
|
||||
// (pTrack->GetDisplay() == WaveTrackViewConstants::Spectrum) ? 1 :
|
||||
0;
|
||||
|
||||
auto title = XO("%s:").Format( pTrack->GetName() );
|
||||
ViewSettingsDialog dialog(
|
||||
mpData->pParent, mpData->project, title, factories, page);
|
||||
|
||||
if (0 != dialog.ShowModal()) {
|
||||
// Redraw
|
||||
AudacityProject *const project = &mpData->project;
|
||||
ProjectHistory::Get( *project ).ModifyState(true);
|
||||
//Bug 1725 Toolbar was left greyed out.
|
||||
//This solution is overkill, but does fix the problem and is what the
|
||||
//prefs dialog normally does.
|
||||
MenuCreator::RebuildAllMenuBars();
|
||||
mpData->result = RefreshCode::RefreshAll;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void WaveTrackMenuTable::OnChannelChange(wxCommandEvent & event)
|
||||
{
|
||||
@ -1137,11 +948,22 @@ void WaveTrackMenuTable::OnSplitStereoMono(wxCommandEvent &)
|
||||
//=============================================================================
|
||||
PopupMenuTable *WaveTrackControls::GetMenuExtension(Track * pTrack)
|
||||
{
|
||||
static Registry::OrderingPreferenceInitializer init{
|
||||
MenuPathStart,
|
||||
{
|
||||
{wxT("/SubViews/Extra"), wxT("WaveColor,SpectrogramSettings")},
|
||||
}
|
||||
};
|
||||
|
||||
WaveTrackMenuTable & result = WaveTrackMenuTable::Instance();
|
||||
return &result;
|
||||
}
|
||||
|
||||
WaveTrackPopupMenuTable &GetWaveTrackMenuTable()
|
||||
{
|
||||
return WaveTrackMenuTable::Instance();
|
||||
}
|
||||
|
||||
// drawing related
|
||||
#include "../../../../widgets/ASlider.h"
|
||||
#include "../../../../TrackInfo.h"
|
||||
@ -1435,3 +1257,4 @@ auto GetDefaultWaveTrackHeight::Implementation() -> Function {
|
||||
};
|
||||
}
|
||||
static GetDefaultWaveTrackHeight registerGetDefaultWaveTrackHeight;
|
||||
|
||||
|
@ -68,4 +68,19 @@ private:
|
||||
std::weak_ptr<PanSliderHandle> mPanHandle;
|
||||
};
|
||||
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
|
||||
struct WaveTrackPopupMenuTable : public PopupMenuTable
|
||||
{
|
||||
using PopupMenuTable::PopupMenuTable;
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
WaveTrack &FindWaveTrack () const;
|
||||
int ReserveId() { return mNextId++; }
|
||||
protected:
|
||||
int mNextId = 0;
|
||||
};
|
||||
|
||||
// Expose the wave track menu table to registration of menu items
|
||||
WaveTrackPopupMenuTable &GetWaveTrackMenuTable();
|
||||
|
||||
#endif
|
||||
|
@ -1039,3 +1039,143 @@ static const WaveTrackSubViews::RegisteredFactory key{
|
||||
return std::make_shared< WaveformView >( view );
|
||||
}
|
||||
};
|
||||
|
||||
// The following attaches the wave color sub-menu to the wave track popup
|
||||
// menu. It is appropriate only to waveform view and so is kept in this
|
||||
// source file with the rest of the waveform view implementation.
|
||||
|
||||
#include <mutex> // for std::call_once
|
||||
#include "WaveTrackControls.h"
|
||||
#include "../../../../widgets/PopupMenuTable.h"
|
||||
#include "../../../../ProjectAudioIO.h"
|
||||
#include "../../../../ProjectHistory.h"
|
||||
#include "../../../../RefreshCode.h"
|
||||
|
||||
//=============================================================================
|
||||
// Table class for a sub-menu
|
||||
struct WaveColorMenuTable : PopupMenuTable
|
||||
{
|
||||
WaveColorMenuTable() : PopupMenuTable{ "WaveColor", XO("&Wave Color") } {}
|
||||
DECLARE_POPUP_MENU(WaveColorMenuTable);
|
||||
|
||||
static WaveColorMenuTable &Instance();
|
||||
|
||||
void InitUserData(void *pUserData) override;
|
||||
|
||||
void DestroyMenu() override
|
||||
{
|
||||
mpData = NULL;
|
||||
}
|
||||
|
||||
PlayableTrackControls::InitMenuData *mpData{};
|
||||
|
||||
int IdOfWaveColor(int WaveColor);
|
||||
void OnWaveColorChange(wxCommandEvent & event);
|
||||
|
||||
int OnInstrument1ID, OnInstrument2ID, OnInstrument3ID, OnInstrument4ID;
|
||||
};
|
||||
|
||||
WaveColorMenuTable &WaveColorMenuTable::Instance()
|
||||
{
|
||||
static WaveColorMenuTable instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WaveColorMenuTable::InitUserData(void *pUserData)
|
||||
{
|
||||
mpData = static_cast<PlayableTrackControls::InitMenuData*>(pUserData);
|
||||
}
|
||||
|
||||
namespace {
|
||||
using ValueFinder = std::function< int( WaveTrack& ) >;
|
||||
|
||||
const TranslatableString GetWaveColorStr(int colorIndex)
|
||||
{
|
||||
return XO("Instrument %i").Format( colorIndex+1 );
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_POPUP_MENU(WaveColorMenuTable)
|
||||
static const auto fn = []( PopupMenuHandler &handler, wxMenu &menu, int id ){
|
||||
auto &me = static_cast<WaveColorMenuTable&>( handler );
|
||||
auto pData = me.mpData;
|
||||
const auto &track = *static_cast<WaveTrack*>(pData->pTrack);
|
||||
auto &project = pData->project;
|
||||
bool unsafe = ProjectAudioIO::Get( project ).IsAudioActive();
|
||||
|
||||
menu.Check( id, id == me.IdOfWaveColor( track.GetWaveColorIndex() ) );
|
||||
menu.Enable( id, !unsafe );
|
||||
};
|
||||
|
||||
static std::once_flag flag;
|
||||
std::call_once( flag, [this]{
|
||||
auto &hostTable = GetWaveTrackMenuTable();
|
||||
OnInstrument1ID = hostTable.ReserveId();
|
||||
OnInstrument2ID = hostTable.ReserveId();
|
||||
OnInstrument3ID = hostTable.ReserveId();
|
||||
OnInstrument4ID = hostTable.ReserveId();
|
||||
} );
|
||||
|
||||
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.
|
||||
int WaveColorMenuTable::IdOfWaveColor(int WaveColor)
|
||||
{ return OnInstrument1ID + WaveColor;}
|
||||
|
||||
/// Handles the selection from the WaveColor submenu of the
|
||||
/// track menu.
|
||||
void WaveColorMenuTable::OnWaveColorChange(wxCommandEvent & event)
|
||||
{
|
||||
int id = event.GetId();
|
||||
wxASSERT(id >= OnInstrument1ID && id <= OnInstrument4ID);
|
||||
const auto pTrack = static_cast<WaveTrack*>(mpData->pTrack);
|
||||
|
||||
int newWaveColor = id - OnInstrument1ID;
|
||||
|
||||
AudacityProject *const project = &mpData->project;
|
||||
|
||||
for (auto channel : TrackList::Channels(pTrack))
|
||||
channel->SetWaveColorIndex(newWaveColor);
|
||||
|
||||
ProjectHistory::Get( *project )
|
||||
.PushState(XO("Changed '%s' to %s")
|
||||
.Format( pTrack->GetName(), GetWaveColorStr(newWaveColor) ),
|
||||
XO("WaveColor Change"));
|
||||
|
||||
using namespace RefreshCode;
|
||||
mpData->result = RefreshAll | FixScrollbars;
|
||||
}
|
||||
|
||||
namespace {
|
||||
PopupMenuTable::AttachedItem sAttachment{
|
||||
GetWaveTrackMenuTable(),
|
||||
{ "SubViews/Extra" },
|
||||
std::make_unique<PopupMenuSection>( "WaveColor",
|
||||
// Conditionally add sub-menu for wave color, if showing waveform
|
||||
PopupMenuTable::Computed< WaveTrackPopupMenuTable >(
|
||||
[]( WaveTrackPopupMenuTable &table ) -> Registry::BaseItemPtr {
|
||||
const auto pTrack = &table.FindWaveTrack();
|
||||
const auto &view = WaveTrackView::Get( *pTrack );
|
||||
const auto displays = view.GetDisplays();
|
||||
bool hasWaveform = (displays.end() != std::find(
|
||||
displays.begin(), displays.end(),
|
||||
WaveTrackSubView::Type{ WaveTrackViewConstants::Waveform, {} }
|
||||
) );
|
||||
if( hasWaveform )
|
||||
return Registry::Shared( WaveColorMenuTable::Instance()
|
||||
.Get( table.mpData ) );
|
||||
else
|
||||
return nullptr;
|
||||
} ) )
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,14 @@ void PopupMenuTable::ExtendMenu( wxMenu &menu, PopupMenuTable &table )
|
||||
theMenu.tables.push_back( &table );
|
||||
|
||||
PopupMenuBuilder visitor{ table, theMenu, theMenu.pUserData };
|
||||
Registry::Visit( visitor, table.Get( theMenu.pUserData ).get() );
|
||||
Registry::Visit(
|
||||
visitor, table.Get( theMenu.pUserData ).get(), table.GetRegistry() );
|
||||
}
|
||||
|
||||
void PopupMenuTable::RegisterItem(
|
||||
const Registry::Placement &placement, Registry::BaseItemPtr pItem )
|
||||
{
|
||||
Registry::RegisterItem( *mRegistry, placement, std::move( pItem ) );
|
||||
}
|
||||
|
||||
void PopupMenuTable::Append( Registry::BaseItemPtr pItem )
|
||||
@ -195,7 +202,8 @@ void PopupMenu::DisconnectTable(PopupMenuTable *pTable)
|
||||
};
|
||||
|
||||
PopupMenuDestroyer visitor{ *pTable, *this };
|
||||
Registry::Visit( visitor, pTable->Get( nullptr ).get() );
|
||||
Registry::Visit( visitor, pTable->Get( nullptr ).get(),
|
||||
pTable->GetRegistry() );
|
||||
}
|
||||
|
||||
void PopupMenu::Disconnect()
|
||||
|
@ -109,6 +109,7 @@ public:
|
||||
PopupMenuTable( const Identifier &id, const TranslatableString &caption = {} )
|
||||
: mId{ id }
|
||||
, mCaption{ caption }
|
||||
, mRegistry{ std::make_unique<Registry::TransparentGroupItem<>>( mId ) }
|
||||
{}
|
||||
|
||||
// Optional pUserData gets passed to the InitUserData routines of tables.
|
||||
@ -118,6 +119,14 @@ public:
|
||||
|
||||
const Identifier &Id() const { return mId; }
|
||||
const TranslatableString &Caption() const { return mCaption; }
|
||||
const Registry::GroupItem *GetRegistry() const { return mRegistry.get(); }
|
||||
|
||||
// Typically statically constructed:
|
||||
struct AttachedItem {
|
||||
AttachedItem( PopupMenuTable &table,
|
||||
const Registry::Placement &placement, Registry::BaseItemPtr pItem )
|
||||
{ table.RegisterItem( placement, std::move( pItem ) ); }
|
||||
};
|
||||
|
||||
// menu must have been built by BuildMenu
|
||||
// More items get added to the end of it
|
||||
@ -132,6 +141,26 @@ public:
|
||||
return mTop;
|
||||
}
|
||||
|
||||
// Forms a computed item, which may be omitted when function returns null
|
||||
// and thus can be a conditional item
|
||||
template< typename Table >
|
||||
static Registry::BaseItemPtr Computed(
|
||||
const std::function< Registry::BaseItemPtr( Table& ) > &factory )
|
||||
{
|
||||
using namespace Registry;
|
||||
return std::make_unique< ComputedItem >(
|
||||
[factory]( Visitor &baseVisitor ){
|
||||
auto &visitor = static_cast< PopupMenuVisitor& >( baseVisitor );
|
||||
auto &table = static_cast< Table& >( visitor.mTable );
|
||||
return factory( table );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
void RegisterItem(
|
||||
const Registry::Placement &placement, Registry::BaseItemPtr pItem );
|
||||
|
||||
protected:
|
||||
virtual void Populate() = 0;
|
||||
|
||||
@ -168,31 +197,30 @@ protected:
|
||||
std::vector< Registry::GroupItem* > mStack;
|
||||
Identifier mId;
|
||||
TranslatableString mCaption;
|
||||
std::unique_ptr<Registry::GroupItem> mRegistry;
|
||||
};
|
||||
|
||||
// A "CRTP" class that injects a convenience function, which appends a menu item
|
||||
// computed lazily by a function that is passed the table (after it has stored
|
||||
// its user data)
|
||||
template< typename Derived >
|
||||
class ComputedPopupMenuTable : public PopupMenuTable
|
||||
template< typename Derived, typename Base = PopupMenuTable >
|
||||
class ComputedPopupMenuTable : public Base
|
||||
{
|
||||
public:
|
||||
using PopupMenuTable::PopupMenuTable;
|
||||
using PopupMenuTable::Append;
|
||||
using Base::Base;
|
||||
using Base::Append;
|
||||
|
||||
// Appends a computed item, which may be omitted when function returns null
|
||||
// and thus can be a conditional item
|
||||
using Factory = std::function< Registry::BaseItemPtr( Derived& ) >;
|
||||
static Registry::BaseItemPtr Computed( const Factory &factory )
|
||||
{
|
||||
return Base::Computed( factory );
|
||||
}
|
||||
|
||||
void Append( const Factory &factory )
|
||||
{
|
||||
using namespace Registry;
|
||||
Append( std::make_unique< ComputedItem >(
|
||||
[factory]( Visitor &baseVisitor ){
|
||||
auto &visitor = static_cast< PopupMenuVisitor& >( baseVisitor );
|
||||
auto &table = static_cast< Derived& >( visitor.mTable );
|
||||
return factory( table );
|
||||
}
|
||||
) );
|
||||
Append( Computed( factory ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user