1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-21 16:37:12 +01: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() {} BaseItem::~BaseItem() {}
SharedItem::~SharedItem() {}
ComputedItem::~ComputedItem() {} ComputedItem::~ComputedItem() {}
SingleItem::~SingleItem() {}
GroupItem::GroupItem( BaseItemPtrs &&items_ ) GroupItem::GroupItem( BaseItemPtrs &&items_ )
: items{ std::move( items_ ) } : items{ std::move( items_ ) }
{ {
@@ -116,6 +120,11 @@ void GroupItem::AppendOne( BaseItemPtr&& ptr )
} }
GroupItem::~GroupItem() {} GroupItem::~GroupItem() {}
TransparentGroupItem::~TransparentGroupItem() {}
}
namespace MenuTable {
MenuItem::MenuItem( const TranslatableString &title_, BaseItemPtrs &&items_ ) MenuItem::MenuItem( const TranslatableString &title_, BaseItemPtrs &&items_ )
: GroupItem{ std::move( items_ ) }, title{ title_ } : GroupItem{ std::move( items_ ) }, title{ title_ }
{ {
@@ -188,6 +197,12 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
auto &manager = CommandManager::Get( project ); auto &manager = CommandManager::Get( project );
using namespace MenuTable; using namespace MenuTable;
if (const auto pShared =
dynamic_cast<SharedItem*>( pItem )) {
auto delegate = pShared->ptr;
VisitItem( project, delegate.get() );
}
else
if (const auto pComputed = if (const auto pComputed =
dynamic_cast<ComputedItem*>( pItem )) { dynamic_cast<ComputedItem*>( pItem )) {
// TODO maybe? memo-ize the results of the function, but that requires // TODO maybe? memo-ize the results of the function, but that requires
@@ -235,7 +250,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
} }
else else
if (const auto pGroup = if (const auto pGroup =
dynamic_cast<GroupItem*>( pItem )) { dynamic_cast<TransparentGroupItem*>( pItem )) {
// recursion // recursion
VisitItems( project, pGroup->items ); VisitItems( project, pGroup->items );
} }

View File

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