mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-21 16:37:12 +01:00
Define abstract Visitor for menu items, and concrete subclass...
... The general visitation procedure will find reuse with other specific actions, and maybe for other non-menu trees too
This commit is contained in:
174
src/Menus.cpp
174
src/Menus.cpp
@@ -121,6 +121,12 @@ void GroupItem::AppendOne( BaseItemPtr&& ptr )
|
|||||||
GroupItem::~GroupItem() {}
|
GroupItem::~GroupItem() {}
|
||||||
|
|
||||||
TransparentGroupItem::~TransparentGroupItem() {}
|
TransparentGroupItem::~TransparentGroupItem() {}
|
||||||
|
|
||||||
|
Visitor::~Visitor(){}
|
||||||
|
void Visitor::BeginGroup(GroupItem &, const Path &) {}
|
||||||
|
void Visitor::EndGroup(GroupItem &, const Path &) {}
|
||||||
|
void Visitor::Visit(SingleItem &, const Path &) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MenuTable {
|
namespace MenuTable {
|
||||||
@@ -250,9 +256,11 @@ using Path = std::vector< Identifier >;
|
|||||||
|
|
||||||
// forward declaration for mutually recursive functions
|
// forward declaration for mutually recursive functions
|
||||||
void VisitItem(
|
void VisitItem(
|
||||||
|
Registry::Visitor &visitor,
|
||||||
AudacityProject &project, CollectedItems &collection,
|
AudacityProject &project, CollectedItems &collection,
|
||||||
Path &path, BaseItem *pItem );
|
Path &path, BaseItem *pItem );
|
||||||
void VisitItems(
|
void VisitItems(
|
||||||
|
Registry::Visitor &visitor,
|
||||||
AudacityProject &project, CollectedItems &collection,
|
AudacityProject &project, CollectedItems &collection,
|
||||||
Path &path, GroupItem *pGroup )
|
Path &path, GroupItem *pGroup )
|
||||||
{
|
{
|
||||||
@@ -265,69 +273,28 @@ void VisitItems(
|
|||||||
// Now visit them
|
// Now visit them
|
||||||
path.push_back( pGroup->name );
|
path.push_back( pGroup->name );
|
||||||
for ( const auto &pSubItem : newCollection.items )
|
for ( const auto &pSubItem : newCollection.items )
|
||||||
VisitItem( project, collection, path, pSubItem );
|
VisitItem( visitor, project, collection, path, pSubItem );
|
||||||
path.pop_back();
|
path.pop_back();
|
||||||
}
|
}
|
||||||
void VisitItem(
|
void VisitItem(
|
||||||
|
Registry::Visitor &visitor,
|
||||||
AudacityProject &project, CollectedItems &collection,
|
AudacityProject &project, CollectedItems &collection,
|
||||||
Path &path, BaseItem *pItem )
|
Path &path, BaseItem *pItem )
|
||||||
{
|
{
|
||||||
if (!pItem)
|
if (!pItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &manager = CommandManager::Get( project );
|
if (const auto pSingle =
|
||||||
|
dynamic_cast<SingleItem*>( pItem )) {
|
||||||
if (const auto pCommand =
|
visitor.Visit( *pSingle, path );
|
||||||
dynamic_cast<CommandItem*>( pItem )) {
|
|
||||||
manager.AddItem( project,
|
|
||||||
pCommand->name, pCommand->label_in,
|
|
||||||
pCommand->finder, pCommand->callback,
|
|
||||||
pCommand->flags, pCommand->options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pCommandList =
|
|
||||||
dynamic_cast<CommandGroupItem*>( pItem ) ) {
|
|
||||||
manager.AddItemList(pCommandList->name,
|
|
||||||
pCommandList->items.data(), pCommandList->items.size(),
|
|
||||||
pCommandList->finder, pCommandList->callback,
|
|
||||||
pCommandList->flags, pCommandList->isEffect);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pMenu =
|
|
||||||
dynamic_cast<MenuItem*>( pItem )) {
|
|
||||||
manager.BeginMenu( pMenu->title );
|
|
||||||
// recursion
|
|
||||||
VisitItems( project, collection, path, pMenu );
|
|
||||||
manager.EndMenu();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pConditionalGroup =
|
|
||||||
dynamic_cast<ConditionalGroupItem*>( pItem )) {
|
|
||||||
const auto flag = pConditionalGroup->condition();
|
|
||||||
if (!flag)
|
|
||||||
manager.BeginOccultCommands();
|
|
||||||
// recursion
|
|
||||||
VisitItems( project, collection, path, pConditionalGroup );
|
|
||||||
if (!flag)
|
|
||||||
manager.EndOccultCommands();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (const auto pGroup =
|
if (const auto pGroup =
|
||||||
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
dynamic_cast<GroupItem*>( pItem )) {
|
||||||
|
visitor.BeginGroup( *pGroup, path );
|
||||||
// recursion
|
// recursion
|
||||||
VisitItems( project, collection, path, pGroup );
|
VisitItems( visitor, project, collection, path, pGroup );
|
||||||
}
|
visitor.EndGroup( *pGroup, path );
|
||||||
else
|
|
||||||
if (dynamic_cast<SeparatorItem*>( pItem )) {
|
|
||||||
manager.AddSeparator();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pSpecial =
|
|
||||||
dynamic_cast<SpecialItem*>( pItem )) {
|
|
||||||
const auto pCurrentMenu = manager.CurrentMenu();
|
|
||||||
wxASSERT( pCurrentMenu );
|
|
||||||
pSpecial->fn( project, *pCurrentMenu );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
wxASSERT( false );
|
wxASSERT( false );
|
||||||
@@ -337,12 +304,14 @@ void VisitItem(
|
|||||||
|
|
||||||
namespace Registry {
|
namespace Registry {
|
||||||
|
|
||||||
void VisitTopItem( AudacityProject &project, BaseItem *pTopItem )
|
void Visit(
|
||||||
|
Visitor &visitor, AudacityProject &project,
|
||||||
|
BaseItem *pTopItem )
|
||||||
{
|
{
|
||||||
std::vector< BaseItemSharedPtr > computedItems;
|
std::vector< BaseItemSharedPtr > computedItems;
|
||||||
CollectedItems collection{ {}, computedItems };
|
CollectedItems collection{ {}, computedItems };
|
||||||
Path emptyPath;
|
Path emptyPath;
|
||||||
VisitItem( project, collection, emptyPath, pTopItem );
|
VisitItem( visitor, project, collection, emptyPath, pTopItem );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -392,6 +361,99 @@ static const auto menuTree = MenuTable::Items( MenuPathStart
|
|||||||
, HelpMenu()
|
, HelpMenu()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct MenuItemVisitor : Registry::Visitor
|
||||||
|
{
|
||||||
|
MenuItemVisitor( AudacityProject &proj, CommandManager &man )
|
||||||
|
: project(proj), manager( man ) {}
|
||||||
|
|
||||||
|
void BeginGroup( GroupItem &item, const Path& ) override
|
||||||
|
{
|
||||||
|
auto pItem = &item;
|
||||||
|
if (const auto pMenu =
|
||||||
|
dynamic_cast<MenuItem*>( pItem )) {
|
||||||
|
manager.BeginMenu( pMenu->title );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pConditionalGroup =
|
||||||
|
dynamic_cast<ConditionalGroupItem*>( pItem )) {
|
||||||
|
const auto flag = pConditionalGroup->condition();
|
||||||
|
if (!flag)
|
||||||
|
manager.BeginOccultCommands();
|
||||||
|
// to avoid repeated call of condition predicate in EndGroup():
|
||||||
|
flags.push_back(flag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pGroup =
|
||||||
|
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wxASSERT( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndGroup( GroupItem &item, const Path& ) override
|
||||||
|
{
|
||||||
|
auto pItem = &item;
|
||||||
|
if (const auto pMenu =
|
||||||
|
dynamic_cast<MenuItem*>( pItem )) {
|
||||||
|
manager.EndMenu();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pConditionalGroup =
|
||||||
|
dynamic_cast<ConditionalGroupItem*>( pItem )) {
|
||||||
|
const bool flag = flags.back();
|
||||||
|
if (!flag)
|
||||||
|
manager.EndOccultCommands();
|
||||||
|
flags.pop_back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pGroup =
|
||||||
|
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wxASSERT( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit( SingleItem &item, const Path& ) override
|
||||||
|
{
|
||||||
|
auto pItem = &item;
|
||||||
|
if (const auto pCommand =
|
||||||
|
dynamic_cast<CommandItem*>( pItem )) {
|
||||||
|
manager.AddItem( project,
|
||||||
|
pCommand->name, pCommand->label_in,
|
||||||
|
pCommand->finder, pCommand->callback,
|
||||||
|
pCommand->flags, pCommand->options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pCommandList =
|
||||||
|
dynamic_cast<CommandGroupItem*>( pItem ) ) {
|
||||||
|
manager.AddItemList(pCommandList->name,
|
||||||
|
pCommandList->items.data(), pCommandList->items.size(),
|
||||||
|
pCommandList->finder, pCommandList->callback,
|
||||||
|
pCommandList->flags, pCommandList->isEffect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (dynamic_cast<SeparatorItem*>( pItem )) {
|
||||||
|
manager.AddSeparator();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pSpecial =
|
||||||
|
dynamic_cast<SpecialItem*>( pItem )) {
|
||||||
|
const auto pCurrentMenu = manager.CurrentMenu();
|
||||||
|
wxASSERT( pCurrentMenu );
|
||||||
|
pSpecial->fn( project, *pCurrentMenu );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wxASSERT( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
AudacityProject &project;
|
||||||
|
CommandManager &manager;
|
||||||
|
std::vector<bool> flags;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
||||||
{
|
{
|
||||||
auto &commandManager = CommandManager::Get( project );
|
auto &commandManager = CommandManager::Get( project );
|
||||||
@@ -403,7 +465,8 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
|||||||
auto menubar = commandManager.AddMenuBar(wxT("appmenu"));
|
auto menubar = commandManager.AddMenuBar(wxT("appmenu"));
|
||||||
wxASSERT(menubar);
|
wxASSERT(menubar);
|
||||||
|
|
||||||
Registry::VisitTopItem( project, menuTree.get() );
|
MenuItemVisitor visitor{ project, commandManager };
|
||||||
|
MenuManager::Visit( visitor, project );
|
||||||
|
|
||||||
GetProjectFrame( project ).SetMenuBar(menubar.release());
|
GetProjectFrame( project ).SetMenuBar(menubar.release());
|
||||||
|
|
||||||
@@ -414,6 +477,11 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuManager::Visit( Registry::Visitor &visitor, AudacityProject &project )
|
||||||
|
{
|
||||||
|
Registry::Visit( visitor, project, menuTree.get() );
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This surely belongs in CommandManager?
|
// TODO: This surely belongs in CommandManager?
|
||||||
void MenuManager::ModifyUndoMenuItems(AudacityProject &project)
|
void MenuManager::ModifyUndoMenuItems(AudacityProject &project)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ enum EffectType : int;
|
|||||||
typedef wxString PluginID;
|
typedef wxString PluginID;
|
||||||
typedef wxArrayString PluginIDs;
|
typedef wxArrayString PluginIDs;
|
||||||
|
|
||||||
|
namespace Registry{ class Visitor; }
|
||||||
|
|
||||||
class MenuCreator
|
class MenuCreator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -68,6 +70,9 @@ public:
|
|||||||
MenuManager &operator=( const MenuManager & ) PROHIBITED;
|
MenuManager &operator=( const MenuManager & ) PROHIBITED;
|
||||||
~MenuManager();
|
~MenuManager();
|
||||||
|
|
||||||
|
static void Visit(
|
||||||
|
Registry::Visitor &visitor, AudacityProject &project );
|
||||||
|
|
||||||
static void ModifyUndoMenuItems(AudacityProject &project);
|
static void ModifyUndoMenuItems(AudacityProject &project);
|
||||||
static void ModifyToolbarMenus(AudacityProject &project);
|
static void ModifyToolbarMenus(AudacityProject &project);
|
||||||
// Calls ModifyToolbarMenus() on all projects
|
// Calls ModifyToolbarMenus() on all projects
|
||||||
|
|||||||
@@ -524,6 +524,23 @@ namespace Registry {
|
|||||||
using GroupItem::GroupItem;
|
using GroupItem::GroupItem;
|
||||||
~TransparentGroupItem() override;
|
~TransparentGroupItem() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Define actions to be done in Visit.
|
||||||
|
// Default implementations do nothing
|
||||||
|
// The supplied path does not include the name of the item
|
||||||
|
class Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Visitor();
|
||||||
|
using Path = std::vector< Identifier >;
|
||||||
|
virtual void BeginGroup( GroupItem &item, const Path &path );
|
||||||
|
virtual void EndGroup( GroupItem &item, const Path &path );
|
||||||
|
virtual void Visit( SingleItem &item, const Path &path );
|
||||||
|
};
|
||||||
|
|
||||||
|
// Top-down visitation of all items and groups in a tree
|
||||||
|
void Visit(
|
||||||
|
Visitor &visitor, AudacityProject &project, BaseItem *pTopItem );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define items that populate tables that specifically describe menu trees
|
// Define items that populate tables that specifically describe menu trees
|
||||||
|
|||||||
Reference in New Issue
Block a user