1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-25 08:58:06 +02:00

Some machinery to add more menu handler object classes...

...without adding linkage dependencies to AudacityProject constructor
This commit is contained in:
Paul Licameli 2018-10-21 19:37:11 -04:00
parent b7f35609ad
commit 280e8d9bac
4 changed files with 120 additions and 5 deletions

View File

@ -171,8 +171,23 @@ static void AddEffectMenuItemGroup(
constexpr size_t kAlignLabelsCount = 5;
static const AudacityProject::RegisteredAttachedObjectFactory factory{ []{
return std::make_unique< MenuCommandHandler >();
} };
PrefsListener::~PrefsListener()
{
}
void PrefsListener::UpdatePrefs()
{
}
MenuCommandHandler &GetMenuCommandHandler(AudacityProject &project)
{ return *project.mMenuCommandHandler; }
{
return static_cast<MenuCommandHandler&>(
project.GetAttachedObject( factory ) );
}
MenuManager &GetMenuManager(AudacityProject &project)
{ return *project.mMenuManager; }

View File

@ -35,8 +35,16 @@ enum EffectType : int;
typedef wxString PluginID;
typedef wxArrayString PluginIDList;
class PrefsListener
{
public:
virtual ~PrefsListener();
virtual void UpdatePrefs(); // default is no-op
};
struct MenuCommandHandler final
: public CommandHandlerObject // MUST be the first base class!
, public PrefsListener
{
MenuCommandHandler();
~MenuCommandHandler();
@ -592,7 +600,7 @@ public:
bool mCircularTrackNavigation{};
wxLongLong mLastSelectionAdjustment;
void UpdatePrefs();
void UpdatePrefs() override;
};
class MenuCreator

View File

@ -98,6 +98,7 @@ scroll information. It also has some status flags.
#include "Dependencies.h"
#include "Diags.h"
#include "HistoryWindow.h"
#include "InconsistencyException.h"
#include "Lyrics.h"
#include "LyricsWindow.h"
#include "MixerBoard.h"
@ -888,6 +889,64 @@ static wxString CreateUniqueName()
wxString::Format(wxT(" N-%i"), ++count);
}
namespace {
#if 0
std::mutex sObjectFactoriesMutex;
struct ObjectFactorySetLocker : private std::unique_lock< std::mutex >
{
ObjectFactorySetLocker()
: std::unique_lock< std::mutex > { sObjectFactoriesMutex }
{}
};
#else
struct ObjectFactorySetLocker {};
#endif
std::vector<AudacityProject::AttachedObjectFactory> &sObjectFactories()
{
// Put this declaration inside a function to avoid problems of undefined
// sequence of initialization of file-scope statics in different
// compilation units.
// Note that mutex locking is not needed for constructing a static object
// in C++11:
//https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
static std::vector<AudacityProject::AttachedObjectFactory> factories;
return factories;
}
}
AudacityProject::
RegisteredAttachedObjectFactory::RegisteredAttachedObjectFactory(
const AttachedObjectFactory &factory )
{
ObjectFactorySetLocker locker;
mIndex = sObjectFactories().size();
sObjectFactories().push_back( factory );
// In case registration happens while projects exist:
for (const auto &pProject : gAudacityProjects) {
if (pProject->mAttachedObjects.size() == mIndex) {
auto pObject = factory();
wxASSERT( pObject );
pProject->mAttachedObjects.push_back( std::move( pObject ) );
}
}
}
AudacityProject::
AttachedObject &AudacityProject::GetAttachedObject(
const RegisteredAttachedObjectFactory &factory )
{
ObjectFactorySetLocker locker;
if ( factory.mIndex >= mAttachedObjects.size() )
THROW_INCONSISTENCY_EXCEPTION;
auto &pObject = mAttachedObjects[ factory.mIndex ];
if ( !pObject )
THROW_INCONSISTENCY_EXCEPTION;
return *pObject;
}
enum {
FirstID = 1000,
@ -982,7 +1041,15 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
// Initialize view info (shared with TrackPanel)
//
mMenuCommandHandler = std::make_unique<MenuCommandHandler>();
{
ObjectFactorySetLocker locker;
for (const auto &factory : sObjectFactories()) {
auto pObject = factory();
wxASSERT( pObject );
mAttachedObjects.push_back( std::move( pObject ) );
}
}
mMenuManager = std::make_unique<MenuManager>();
UpdatePrefs();
@ -1364,7 +1431,12 @@ void AudacityProject::UpdatePrefs()
SetProjectTitle();
GetMenuCommandHandler(*this).UpdatePrefs();
{
ObjectFactorySetLocker locker;
for( const auto &pObject : mAttachedObjects )
pObject->UpdatePrefs();
}
GetMenuManager(*this).UpdatePrefs();
if (mTrackPanel) {

View File

@ -172,6 +172,8 @@ class WaveTrack;
struct MenuCommandHandler;
class MenuManager;
class PrefsListener;
class AUDACITY_DLL_API AudacityProject final : public wxFrame,
public TrackPanelListener,
public SelectionBarListener,
@ -184,6 +186,24 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame,
const wxPoint & pos, const wxSize & size);
virtual ~AudacityProject();
using AttachedObject = PrefsListener;
using AttachedObjectFactory =
std::function< std::unique_ptr<AttachedObject>() >;
// Typically a static object. Allows various application code to
// attach per-project state, without Project.cpp needing to include a header
// file or know the details.
class RegisteredAttachedObjectFactory {
public:
RegisteredAttachedObjectFactory( const AttachedObjectFactory &factory );
private:
friend AudacityProject;
size_t mIndex {};
};
AttachedObject &
GetAttachedObject( const RegisteredAttachedObjectFactory& factory );
virtual void ApplyUpdatedTheme();
AudioIOStartStreamOptions GetDefaultPlayOptions();
@ -807,7 +827,7 @@ private:
#endif
private:
std::unique_ptr<MenuCommandHandler> mMenuCommandHandler;
std::vector< std::unique_ptr<AttachedObject> > mAttachedObjects;
std::unique_ptr<MenuManager> mMenuManager;
public: