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:
@@ -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 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user