1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-17 00:20:06 +02:00

Define AttachedItem registration struct for menu items

This commit is contained in:
Paul Licameli 2019-01-04 09:37:42 -05:00
parent c5495b3300
commit baada94567
2 changed files with 114 additions and 4 deletions

View File

@ -178,6 +178,78 @@ CommandHandlerFinder FinderScope::sFinder =
} }
namespace Registry {
void RegisterItem( GroupItem &registry, const Placement &placement,
BaseItemPtr pItem )
{
// Since registration determines only an unordered tree of menu items,
// we can sort children of each node lexicographically for our convenience.
BaseItemPtrs *pItems;
struct Comparator {
bool operator()
( const Identifier &component, const BaseItemPtr& pItem ) const {
return component < pItem->name; }
bool operator()
( const BaseItemPtr& pItem, const Identifier &component ) const {
return pItem->name < component; }
};
auto find = [&pItems]( const Identifier &component ){ return std::equal_range(
pItems->begin(), pItems->end(), component, Comparator() ); };
auto pNode = &registry;
pItems = &pNode->items;
auto pathComponents = ::wxSplit( placement.path, '/' );
auto pComponent = pathComponents.begin(), end = pathComponents.end();
// Descend the registry hierarchy, while groups matching the path components
// can be found
auto debugPath = wxString{'/'} + registry.name.GET();
while ( pComponent != end ) {
const auto &pathComponent = *pComponent;
// Try to find an item already present that is a group item with the
// same name; we don't care which if there is more than one.
const auto range = find( pathComponent );
const auto iter2 = std::find_if( range.first, range.second,
[](const BaseItemPtr &pItem){
return dynamic_cast< GroupItem* >( pItem.get() ); } );
if ( iter2 != range.second ) {
// A matching group in the registry, so descend
pNode = static_cast< GroupItem* >( iter2->get() );
pItems = &pNode->items;
debugPath += '/' + pathComponent;
++pComponent;
}
else
// Insert at this level;
// If there are no more path components, and a name collision of
// the added item with something already in the registry, don't resolve
// it yet in this function, but see MergeItems().
break;
}
// Create path group items for remaining components
while ( pComponent != end ) {
auto newNode = std::make_unique<TransparentGroupItem<>>( *pComponent );
pNode = newNode.get();
pItems->insert( find( newNode->name ).second, std::move( newNode ) );
pItems = &pNode->items;
++pComponent;
}
// Remember the hint, to be used later in merging.
pItem->orderingHint = placement.hint;
// Now insert the item.
pItems->insert( find( pItem->name ).second, std::move( pItem ) );
}
}
namespace { namespace {
const auto MenuPathStart = wxT("MenuBar"); const auto MenuPathStart = wxT("MenuBar");
@ -301,7 +373,6 @@ void CollectItem( Registry::Visitor &visitor,
using Path = std::vector< Identifier >; using Path = std::vector< Identifier >;
namespace {
std::unordered_set< wxString > sBadPaths; std::unordered_set< wxString > sBadPaths;
void BadPath( void BadPath(
const TranslatableString &format, const wxString &key, const Identifier &name ) const TranslatableString &format, const wxString &key, const Identifier &name )
@ -339,7 +410,6 @@ XO("Plug-in item at %s conflicts with a previously defined item and was discarde
XO("Plug-in items at %s specify conflicting placements"), XO("Plug-in items at %s specify conflicting placements"),
key, name); key, name);
} }
}
struct ItemOrdering { struct ItemOrdering {
wxString key; wxString key;
@ -763,6 +833,12 @@ static Registry::GroupItem &sRegistry()
} }
} }
MenuTable::AttachedItem::AttachedItem(
const Placement &placement, BaseItemPtr pItem )
{
Registry::RegisterItem( sRegistry(), placement, std::move( pItem ) );
}
// Table of menu factories. // Table of menu factories.
// TODO: devise a registration system instead. // TODO: devise a registration system instead.
static const auto menuTree = MenuTable::Items( MenuPathStart static const auto menuTree = MenuTable::Items( MenuPathStart

View File

@ -602,6 +602,25 @@ namespace Registry {
~TransparentGroupItem() override {} ~TransparentGroupItem() override {}
}; };
// The /-separated path is relative to the GroupItem supplied to
// RegisterItem.
// For instance, wxT("Transport/Cursor") to locate an item under a sub-menu
// of a main menu
struct Placement {
wxString path;
OrderingHint hint;
Placement( const wxString &path_, const OrderingHint &hint_ = {} )
: path( path_ ), hint( hint_ )
{}
};
// registry collects items, before consulting preferences and ordering
// hints, and applying the merge procedure to them.
// This function puts one more item into the registry.
void RegisterItem( GroupItem &registry, const Placement &placement,
BaseItemPtr pItem );
// Define actions to be done in Visit. // Define actions to be done in Visit.
// Default implementations do nothing // Default implementations do nothing
// The supplied path does not include the name of the item // The supplied path does not include the name of the item
@ -800,7 +819,8 @@ namespace MenuTable {
using MenuItems = MenuPart< true >; using MenuItems = MenuPart< true >;
using MenuSection = MenuPart< false >; using MenuSection = MenuPart< false >;
// Following are the functions to use directly in writing table definitions. // The following, and Shared(), are the functions to use directly
// in writing table definitions.
// Group items can be constructed two ways. // Group items can be constructed two ways.
// Pointers to subordinate items are moved into the result. // Pointers to subordinate items are moved into the result.
@ -913,6 +933,20 @@ namespace MenuTable {
inline std::unique_ptr<SpecialItem> Special( inline std::unique_ptr<SpecialItem> Special(
const wxString &name, const SpecialItem::Appender &fn ) const wxString &name, const SpecialItem::Appender &fn )
{ return std::make_unique<SpecialItem>( name, fn ); } { return std::make_unique<SpecialItem>( name, fn ); }
// Typically you make a static object of this type in the .cpp file that
// also defines the added menu actions.
// pItem can be specified by an expression using the inline functions above.
struct AttachedItem final
{
AttachedItem( const Placement &placement, BaseItemPtr pItem );
AttachedItem( const wxString &path, BaseItemPtr pItem )
// Delegating constructor
: AttachedItem( Placement{ path }, std::move( pItem ) )
{}
};
} }
#endif #endif