mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-21 16:37:12 +01:00
Visiting of menu items calculates paths (not yet used)...
... Computed, shared, and nameless grouping items don't (directly) affect paths, and are expanded in a first pass before visiting the real items
This commit is contained in:
130
src/Menus.cpp
130
src/Menus.cpp
@@ -183,39 +183,100 @@ namespace {
|
|||||||
|
|
||||||
const auto MenuPathStart = wxT("MenuBar");
|
const auto MenuPathStart = wxT("MenuBar");
|
||||||
|
|
||||||
void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem );
|
using namespace MenuTable;
|
||||||
|
struct CollectedItems
|
||||||
void VisitItems(
|
|
||||||
AudacityProject &project, const MenuTable::BaseItemPtrs &items )
|
|
||||||
{
|
{
|
||||||
for ( auto &pSubItem : items )
|
std::vector< BaseItem * > items;
|
||||||
VisitItem( project, pSubItem.get() );
|
std::vector< BaseItemSharedPtr > &computedItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
// "Collection" of items is the first pass of visitation, and resolves
|
||||||
|
// delegation and delayed computation and splices transparent group nodes.
|
||||||
|
// This first pass is done at each group, starting with a top-level group.
|
||||||
|
// This pass does not descend to the leaves. Rather, the visitation passes
|
||||||
|
// alternate as the entire tree is recursively visited.
|
||||||
|
|
||||||
|
// forward declaration for mutually recursive functions
|
||||||
|
void CollectItem( AudacityProject &project,
|
||||||
|
CollectedItems &collection, BaseItem *Item );
|
||||||
|
void CollectItems( AudacityProject &project,
|
||||||
|
CollectedItems &collection, const BaseItemPtrs &items )
|
||||||
|
{
|
||||||
|
for ( auto &item : items )
|
||||||
|
CollectItem( project, collection, item.get() );
|
||||||
|
}
|
||||||
|
void CollectItem( AudacityProject &project,
|
||||||
|
CollectedItems &collection, BaseItem *pItem )
|
||||||
|
{
|
||||||
|
if (!pItem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using namespace MenuTable;
|
||||||
|
if (const auto pShared =
|
||||||
|
dynamic_cast<SharedItem*>( pItem )) {
|
||||||
|
auto &delegate = pShared->ptr;
|
||||||
|
// recursion
|
||||||
|
CollectItem( project, collection, delegate.get() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (const auto pComputed =
|
||||||
|
dynamic_cast<ComputedItem*>( pItem )) {
|
||||||
|
auto result = pComputed->factory( project );
|
||||||
|
if (result) {
|
||||||
|
// Guarantee long enough lifetime of the result
|
||||||
|
collection.computedItems.push_back( result );
|
||||||
|
// recursion
|
||||||
|
CollectItem( project, collection, result.get() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (auto pGroup = dynamic_cast<GroupItem*>(pItem)) {
|
||||||
|
if (dynamic_cast<TransparentGroupItem*>(pItem) && pItem->name.empty())
|
||||||
|
// nameless grouping item is transparent to path calculations
|
||||||
|
// recursion
|
||||||
|
CollectItems( project, collection, pGroup->items );
|
||||||
|
else
|
||||||
|
// all other group items
|
||||||
|
collection.items.push_back( pItem );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wxASSERT( dynamic_cast<SingleItem*>(pItem) );
|
||||||
|
// common to all single items
|
||||||
|
collection.items.push_back( pItem );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
|
using Path = std::vector< Identifier >;
|
||||||
|
|
||||||
|
// forward declaration for mutually recursive functions
|
||||||
|
void VisitItem(
|
||||||
|
AudacityProject &project, CollectedItems &collection,
|
||||||
|
Path &path, BaseItem *pItem );
|
||||||
|
void VisitItems(
|
||||||
|
AudacityProject &project, CollectedItems &collection,
|
||||||
|
Path &path, GroupItem *pGroup )
|
||||||
|
{
|
||||||
|
// Make a new collection for this subtree, sharing the memo cache
|
||||||
|
CollectedItems newCollection{ {}, collection.computedItems };
|
||||||
|
|
||||||
|
// Gather items at this level
|
||||||
|
CollectItems( project, newCollection, pGroup->items );
|
||||||
|
|
||||||
|
// Now visit them
|
||||||
|
path.push_back( pGroup->name );
|
||||||
|
for ( const auto &pSubItem : newCollection.items )
|
||||||
|
VisitItem( project, collection, path, pSubItem );
|
||||||
|
path.pop_back();
|
||||||
|
}
|
||||||
|
void VisitItem(
|
||||||
|
AudacityProject &project, CollectedItems &collection,
|
||||||
|
Path &path, BaseItem *pItem )
|
||||||
{
|
{
|
||||||
if (!pItem)
|
if (!pItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &manager = CommandManager::Get( project );
|
auto &manager = CommandManager::Get( project );
|
||||||
|
|
||||||
using namespace MenuTable;
|
|
||||||
if (const auto pShared =
|
|
||||||
dynamic_cast<SharedItem*>( pItem )) {
|
|
||||||
auto delegate = pShared->ptr;
|
|
||||||
VisitItem( project, delegate.get() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pComputed =
|
|
||||||
dynamic_cast<ComputedItem*>( pItem )) {
|
|
||||||
// TODO maybe? memo-ize the results of the function, but that requires
|
|
||||||
// invalidating the memo at the right times
|
|
||||||
auto result = pComputed->factory( project );
|
|
||||||
if (result)
|
|
||||||
// recursion
|
|
||||||
VisitItem( project, result.get() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (const auto pCommand =
|
if (const auto pCommand =
|
||||||
dynamic_cast<CommandItem*>( pItem )) {
|
dynamic_cast<CommandItem*>( pItem )) {
|
||||||
manager.AddItem( project,
|
manager.AddItem( project,
|
||||||
@@ -237,7 +298,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
|
|||||||
dynamic_cast<MenuItem*>( pItem )) {
|
dynamic_cast<MenuItem*>( pItem )) {
|
||||||
manager.BeginMenu( pMenu->title );
|
manager.BeginMenu( pMenu->title );
|
||||||
// recursion
|
// recursion
|
||||||
VisitItems( project, pMenu->items );
|
VisitItems( project, collection, path, pMenu );
|
||||||
manager.EndMenu();
|
manager.EndMenu();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -247,7 +308,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
|
|||||||
if (!flag)
|
if (!flag)
|
||||||
manager.BeginOccultCommands();
|
manager.BeginOccultCommands();
|
||||||
// recursion
|
// recursion
|
||||||
VisitItems( project, pConditionalGroup->items );
|
VisitItems( project, collection, path, pConditionalGroup );
|
||||||
if (!flag)
|
if (!flag)
|
||||||
manager.EndOccultCommands();
|
manager.EndOccultCommands();
|
||||||
}
|
}
|
||||||
@@ -255,7 +316,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
|
|||||||
if (const auto pGroup =
|
if (const auto pGroup =
|
||||||
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
dynamic_cast<TransparentGroupItem*>( pItem )) {
|
||||||
// recursion
|
// recursion
|
||||||
VisitItems( project, pGroup->items );
|
VisitItems( project, collection, path, pGroup );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (dynamic_cast<SeparatorItem*>( pItem )) {
|
if (dynamic_cast<SeparatorItem*>( pItem )) {
|
||||||
@@ -274,6 +335,18 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Registry {
|
||||||
|
|
||||||
|
void VisitTopItem( AudacityProject &project, BaseItem *pTopItem )
|
||||||
|
{
|
||||||
|
std::vector< BaseItemSharedPtr > computedItems;
|
||||||
|
CollectedItems collection{ {}, computedItems };
|
||||||
|
Path emptyPath;
|
||||||
|
VisitItem( project, collection, emptyPath, pTopItem );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// CreateMenusAndCommands builds the menus, and also rebuilds them after
|
/// CreateMenusAndCommands builds the menus, and also rebuilds them after
|
||||||
/// changes in configured preferences - for example changes in key-bindings
|
/// changes in configured preferences - for example changes in key-bindings
|
||||||
/// affect the short-cut key legend that appears beside each command,
|
/// affect the short-cut key legend that appears beside each command,
|
||||||
@@ -330,7 +403,8 @@ void MenuCreator::CreateMenusAndCommands(AudacityProject &project)
|
|||||||
auto menubar = commandManager.AddMenuBar(wxT("appmenu"));
|
auto menubar = commandManager.AddMenuBar(wxT("appmenu"));
|
||||||
wxASSERT(menubar);
|
wxASSERT(menubar);
|
||||||
|
|
||||||
VisitItem( project, menuTree.get() );
|
Registry::VisitTopItem( project, menuTree.get() );
|
||||||
|
|
||||||
GetProjectFrame( project ).SetMenuBar(menubar.release());
|
GetProjectFrame( project ).SetMenuBar(menubar.release());
|
||||||
|
|
||||||
mLastFlags = AlwaysEnabledFlag;
|
mLastFlags = AlwaysEnabledFlag;
|
||||||
|
|||||||
Reference in New Issue
Block a user