mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-17 16:50:26 +02: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:
parent
4eee417ded
commit
356e5d545e
174
src/Menus.cpp
174
src/Menus.cpp
@ -121,6 +121,12 @@ void GroupItem::AppendOne( BaseItemPtr&& ptr )
|
||||
GroupItem::~GroupItem() {}
|
||||
|
||||
TransparentGroupItem::~TransparentGroupItem() {}
|
||||
|
||||
Visitor::~Visitor(){}
|
||||
void Visitor::BeginGroup(GroupItem &, const Path &) {}
|
||||
void Visitor::EndGroup(GroupItem &, const Path &) {}
|
||||
void Visitor::Visit(SingleItem &, const Path &) {}
|
||||
|
||||
}
|
||||
|
||||
namespace MenuTable {
|
||||
@ -250,9 +256,11 @@ using Path = std::vector< Identifier >;
|
||||
|
||||
// forward declaration for mutually recursive functions
|
||||
void VisitItem(
|
||||
Registry::Visitor &visitor,
|
||||
AudacityProject &project, CollectedItems &collection,
|
||||
Path &path, BaseItem *pItem );
|
||||
void VisitItems(
|
||||
Registry::Visitor &visitor,
|
||||
AudacityProject &project, CollectedItems &collection,
|
||||
Path &path, GroupItem *pGroup )
|
||||
{
|
||||
@ -265,69 +273,28 @@ void VisitItems(
|
||||
// Now visit them
|
||||
path.push_back( pGroup->name );
|
||||
for ( const auto &pSubItem : newCollection.items )
|
||||
VisitItem( project, collection, path, pSubItem );
|
||||
VisitItem( visitor, project, collection, path, pSubItem );
|
||||
path.pop_back();
|
||||
}
|
||||
void VisitItem(
|
||||
Registry::Visitor &visitor,
|
||||
AudacityProject &project, CollectedItems &collection,
|
||||
Path &path, BaseItem *pItem )
|
||||
{
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
auto &manager = CommandManager::Get( project );
|
||||
|
||||
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 (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();
|
||||
if (const auto pSingle =
|
||||
dynamic_cast<SingleItem*>( pItem )) {
|
||||
visitor.Visit( *pSingle, path );
|
||||
}
|
||||
else
|
||||
if (const auto pGroup =
|
||||
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
||||
dynamic_cast<GroupItem*>( pItem )) {
|
||||
visitor.BeginGroup( *pGroup, path );
|
||||
// recursion
|
||||
VisitItems( project, collection, path, pGroup );
|
||||
}
|
||||
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 );
|
||||
VisitItems( visitor, project, collection, path, pGroup );
|
||||
visitor.EndGroup( *pGroup, path );
|
||||
}
|
||||
else
|
||||
wxASSERT( false );
|
||||
@ -337,12 +304,14 @@ void VisitItem(
|
||||
|
||||
namespace Registry {
|
||||
|
||||
void VisitTopItem( AudacityProject &project, BaseItem *pTopItem )
|
||||
void Visit(
|
||||
Visitor &visitor, AudacityProject &project,
|
||||
BaseItem *pTopItem )
|
||||
{
|
||||
std::vector< BaseItemSharedPtr > computedItems;
|
||||
CollectedItems collection{ {}, computedItems };
|
||||
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()
|
||||
);
|
||||
|
||||
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)
|
||||
{
|
||||
auto &commandManager = CommandManager::Get( project );
|
||||
@ -403,7 +465,8 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
||||
auto menubar = commandManager.AddMenuBar(wxT("appmenu"));
|
||||
wxASSERT(menubar);
|
||||
|
||||
Registry::VisitTopItem( project, menuTree.get() );
|
||||
MenuItemVisitor visitor{ project, commandManager };
|
||||
MenuManager::Visit( visitor, project );
|
||||
|
||||
GetProjectFrame( project ).SetMenuBar(menubar.release());
|
||||
|
||||
@ -414,6 +477,11 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
||||
#endif
|
||||
}
|
||||
|
||||
void MenuManager::Visit( Registry::Visitor &visitor, AudacityProject &project )
|
||||
{
|
||||
Registry::Visit( visitor, project, menuTree.get() );
|
||||
}
|
||||
|
||||
// TODO: This surely belongs in CommandManager?
|
||||
void MenuManager::ModifyUndoMenuItems(AudacityProject &project)
|
||||
{
|
||||
|
@ -35,6 +35,8 @@ enum EffectType : int;
|
||||
typedef wxString PluginID;
|
||||
typedef wxArrayString PluginIDs;
|
||||
|
||||
namespace Registry{ class Visitor; }
|
||||
|
||||
class MenuCreator
|
||||
{
|
||||
public:
|
||||
@ -68,6 +70,9 @@ public:
|
||||
MenuManager &operator=( const MenuManager & ) PROHIBITED;
|
||||
~MenuManager();
|
||||
|
||||
static void Visit(
|
||||
Registry::Visitor &visitor, AudacityProject &project );
|
||||
|
||||
static void ModifyUndoMenuItems(AudacityProject &project);
|
||||
static void ModifyToolbarMenus(AudacityProject &project);
|
||||
// Calls ModifyToolbarMenus() on all projects
|
||||
|
@ -524,6 +524,23 @@ namespace Registry {
|
||||
using GroupItem::GroupItem;
|
||||
~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
|
||||
|
Loading…
x
Reference in New Issue
Block a user