1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-01 16:19:43 +02:00

Change class hierarchy of MenuTable::BaseItem...

... There are now four immediate subclasses (SharedItem and Computed Item,
which are final, and SingleItem and GroupItem, which are abstract), which may
serve future purposes more general than menu items.  There are further
subclasses specific to menu management.

The former concrete class GroupItem is renamed TransparentGroupItem.

Also allows direct construction of items in lists from shared pointers.
This commit is contained in:
Paul Licameli 2019-01-01 13:53:46 -05:00
parent 93c2bb9322
commit 33b4b409e8
2 changed files with 78 additions and 18 deletions

View File

@ -104,8 +104,12 @@ namespace MenuTable {
BaseItem::~BaseItem() {}
SharedItem::~SharedItem() {}
ComputedItem::~ComputedItem() {}
SingleItem::~SingleItem() {}
GroupItem::GroupItem( BaseItemPtrs &&items_ )
: items{ std::move( items_ ) }
{
@ -116,6 +120,11 @@ void GroupItem::AppendOne( BaseItemPtr&& ptr )
}
GroupItem::~GroupItem() {}
TransparentGroupItem::~TransparentGroupItem() {}
}
namespace MenuTable {
MenuItem::MenuItem( const TranslatableString &title_, BaseItemPtrs &&items_ )
: GroupItem{ std::move( items_ ) }, title{ title_ }
{
@ -188,6 +197,12 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
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
@ -235,7 +250,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
}
else
if (const auto pGroup =
dynamic_cast<GroupItem*>( pItem )) {
dynamic_cast<TransparentGroupItem*>( pItem )) {
// recursion
VisitItems( project, pGroup->items );
}

View File

@ -405,7 +405,8 @@ private:
std::unique_ptr< wxMenuBar > mTempMenuBar;
};
// Define items that populate tables that describe menu trees
// Define classes and functions that associate parts of the user interface
// with path names
namespace MenuTable {
// TODO C++17: maybe use std::variant (discriminated unions) to achieve
// polymorphism by other means, not needing unique_ptr and dynamic_cast
@ -418,18 +419,34 @@ namespace MenuTable {
virtual ~BaseItem();
};
using BaseItemPtr = std::unique_ptr<BaseItem>;
using BaseItemSharedPtr = std::shared_ptr<BaseItem>;
using BaseItemPtrs = std::vector<BaseItemPtr>;
// The type of functions that generate menu table descriptions.
// Return type is a shared_ptr to let the function decide whether to recycle
// the object or rebuild it on demand each time.
// Return value from the factory may be null.
using Factory = std::function<
std::shared_ptr< MenuTable::BaseItem >( AudacityProject & )
>;
// An item that delegates to another held in a shared pointer; this allows
// static tables of items to be computed once and reused
struct SharedItem final : BaseItem {
explicit SharedItem( const BaseItemSharedPtr &ptr_ )
: ptr{ ptr_ }
{}
~SharedItem() override;
BaseItemSharedPtr ptr;
};
// A convenience function
inline std::unique_ptr<SharedItem> Shared( const BaseItemSharedPtr &ptr )
{ return std::make_unique<SharedItem>( ptr ); }
// An item that computes some other item to substitute for it, each time
// the ComputedItem is visited
struct ComputedItem final : BaseItem {
// The type of functions that generate descriptions of items.
// Return type is a shared_ptr to let the function decide whether to
// recycle the object or rebuild it on demand each time.
// Return value from the factory may be null
using Factory = std::function< BaseItemSharedPtr( AudacityProject & ) >;
struct ComputedItem : BaseItem {
explicit ComputedItem( const Factory &factory_ )
: factory{ factory_ }
{}
@ -438,6 +455,13 @@ namespace MenuTable {
Factory factory;
};
// Common abstract base class for items that are not groups
struct SingleItem : BaseItem {
using BaseItem::BaseItem;
~SingleItem() override = 0;
};
// Common abstract base class for items that group other items
struct GroupItem : BaseItem {
// Construction from a previously built-up vector of pointers
GroupItem( BaseItemPtrs &&items_ );
@ -445,7 +469,7 @@ namespace MenuTable {
template< typename... Args >
GroupItem( Args&&... args )
{ Append( std::forward< Args >( args )... ); }
~GroupItem() override;
~GroupItem() override = 0;
BaseItemPtrs items;
@ -473,10 +497,24 @@ namespace MenuTable {
// (Thus, a lambda can return a unique_ptr<BaseItem> rvalue even though
// Factory's return type is shared_ptr, and the needed conversion is
// appled implicitly.)
void AppendOne( const Factory &factory )
void AppendOne( const ComputedItem::Factory &factory )
{ AppendOne( std::make_unique<ComputedItem>( factory ) ); }
// This overload lets you supply a shared pointer to an item, directly
template<typename Subtype>
void AppendOne( const std::shared_ptr<Subtype> &ptr )
{ AppendOne( std::make_unique<SharedItem>(ptr) ); }
};
// Concrete subclass of GroupItem that adds nothing else
struct TransparentGroupItem final : GroupItem
{
using GroupItem::GroupItem;
~TransparentGroupItem() override;
};
// Define items that populate tables that specifically describe menu trees
// Describes a main menu in the toolbar, or a sub-menu
struct MenuItem final : GroupItem {
// Construction from a previously built-up vector of pointers
MenuItem( const TranslatableString &title_, BaseItemPtrs &&items_ );
@ -492,6 +530,8 @@ namespace MenuTable {
TranslatableString title;
};
// Collects other items that are conditionally shown or hidden, but are
// always available to macro programming
struct ConditionalGroupItem final : GroupItem {
using Condition = std::function< bool() >;
@ -508,7 +548,8 @@ namespace MenuTable {
Condition condition;
};
struct SeparatorItem final : BaseItem
// Describes a separator between menu items
struct SeparatorItem final : SingleItem
{
~SeparatorItem() override;
};
@ -542,7 +583,8 @@ namespace MenuTable {
{ return std::forward<Value>(value); }
};
struct CommandItem final : BaseItem {
// Describes one command in a menu
struct CommandItem final : SingleItem {
CommandItem(const CommandID &name_,
const TranslatableString &label_in_,
CommandFunctorPointer callback_,
@ -574,7 +616,10 @@ namespace MenuTable {
CommandManager::Options options;
};
struct CommandGroupItem final : BaseItem {
// Describes several successive commands in a menu that are closely related
// and dispatch to one common callback, which will be passed a number
// in the CommandContext identifying the command
struct CommandGroupItem final : SingleItem {
CommandGroupItem(const wxString &name_,
std::initializer_list< ComponentInterfaceSymbol > items_,
CommandFunctorPointer callback_,
@ -608,7 +653,7 @@ namespace MenuTable {
// For manipulating the enclosing menu or sub-menu directly,
// adding any number of items, not using the CommandManager
struct SpecialItem final : BaseItem
struct SpecialItem final : SingleItem
{
using Appender = std::function< void( AudacityProject&, wxMenu& ) >;
@ -627,8 +672,8 @@ namespace MenuTable {
// Null pointers are permitted, and ignored when building the menu.
// Items are spliced into the enclosing menu
template< typename... Args >
inline std::unique_ptr<GroupItem> Items( Args&&... args )
{ return std::make_unique<GroupItem>(
inline std::unique_ptr<TransparentGroupItem> Items( Args&&... args )
{ return std::make_unique<TransparentGroupItem>(
std::forward<Args>(args)... ); }
// Menu items can be constructed two ways, as for group items