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:
parent
c5495b3300
commit
baada94567
@ -178,6 +178,78 @@ CommandHandlerFinder FinderScope::sFinder =
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Registry {
|
||||||
|
|
||||||
|
void RegisterItem( GroupItem ®istry, 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 = ®istry;
|
||||||
|
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
|
||||||
|
@ -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 ®istry, 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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user