1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-10 17:37:45 +02:00

Menu descriptions mostly computed once only & have string identifiers

This commit is contained in:
Paul Licameli 2020-01-24 18:24:43 -05:00
commit c77d4e1961
22 changed files with 795 additions and 417 deletions

View File

@ -113,7 +113,7 @@ void ModNullCallback::OnFuncSecond(const CommandContext &)
}
ModNullCallback * pModNullCallback=NULL;
#define ModNullFN(X) ident, static_cast<CommandFunctorPointer>(&ModNullCallback:: X)
#define ModNullFN(X) static_cast<CommandFunctorPointer>((&ModNullCallback:: X))
extern "C" {
@ -160,15 +160,15 @@ int ModuleDispatch(ModuleDispatchTypes type)
c->SetCurrentMenu( pMenu );
c->AddSeparator();
// We add two new commands into the Analyze menu.
c->AddItem(
c->AddItem( *p,
_T("A New Command"), // internal name
XO("1st Experimental Command..."), //displayed name
ModNullFN( OnFuncFirst ),
ident, ModNullFN( OnFuncFirst ),
AudioIONotBusyFlag );
c->AddItem(
_T("Another New Command"),
c->AddItem( *p,
_T("Another New Command"),
XO("2nd Experimental Command"),
ModNullFN( OnFuncSecond ),
ident, ModNullFN( OnFuncSecond ),
AudioIONotBusyFlag );
c->ClearCurrentMenu();
}

View File

@ -195,7 +195,7 @@ extern "C"
c->SetCurrentMenu(pMenu);
c->AddSeparator();
c->AddItem(wxT("NyqBench"),
c->AddItem( *p, wxT("NyqBench"),
XO("&Nyquist Workbench..."),
findme,
static_cast<CommandFunctorPointer>(&NyqBench::ShowNyqBench),

View File

@ -104,10 +104,14 @@ namespace MenuTable {
BaseItem::~BaseItem() {}
SharedItem::~SharedItem() {}
ComputedItem::~ComputedItem() {}
GroupItem::GroupItem( BaseItemPtrs &&items_ )
: items{ std::move( items_ ) }
SingleItem::~SingleItem() {}
GroupItem::GroupItem( const wxString &internalName, BaseItemPtrs &&items_ )
: BaseItem{ internalName }, items{ std::move( items_ ) }
{
}
void GroupItem::AppendOne( BaseItemPtr&& ptr )
@ -116,16 +120,22 @@ void GroupItem::AppendOne( BaseItemPtr&& ptr )
}
GroupItem::~GroupItem() {}
MenuItem::MenuItem( const TranslatableString &title_, BaseItemPtrs &&items_ )
: GroupItem{ std::move( items_ ) }, title{ title_ }
TransparentGroupItem::~TransparentGroupItem() {}
}
namespace MenuTable {
MenuItem::MenuItem( const wxString &internalName,
const TranslatableString &title_, BaseItemPtrs &&items_ )
: GroupItem{ internalName, std::move( items_ ) }, title{ title_ }
{
wxASSERT( !title.empty() );
}
MenuItem::~MenuItem() {}
ConditionalGroupItem::ConditionalGroupItem(
Condition condition_, BaseItemPtrs &&items_ )
: GroupItem{ std::move( items_ ) }, condition{ condition_ }
const wxString &internalName, Condition condition_, BaseItemPtrs &&items_ )
: GroupItem{ internalName, std::move( items_ ) }, condition{ condition_ }
{
}
ConditionalGroupItem::~ConditionalGroupItem() {}
@ -134,11 +144,11 @@ SeparatorItem::~SeparatorItem() {}
CommandItem::CommandItem(const CommandID &name_,
const TranslatableString &label_in_,
CommandHandlerFinder finder_,
CommandFunctorPointer callback_,
CommandFlag flags_,
const CommandManager::Options &options_)
: name{ name_ }, label_in{ label_in_ }
const CommandManager::Options &options_,
CommandHandlerFinder finder_)
: SingleItem{ name_ }, label_in{ label_in_ }
, finder{ finder_ }, callback{ callback_ }
, flags{ flags_ }, options{ options_ }
{}
@ -146,11 +156,11 @@ CommandItem::~CommandItem() {}
CommandGroupItem::CommandGroupItem(const wxString &name_,
std::initializer_list< ComponentInterfaceSymbol > items_,
CommandHandlerFinder finder_,
CommandFunctorPointer callback_,
CommandFlag flags_,
bool isEffect_)
: name{ name_ }, items{ items_ }
bool isEffect_,
CommandHandlerFinder finder_)
: SingleItem{ name_ }, items{ items_ }
, finder{ finder_ }, callback{ callback_ }
, flags{ flags_ }, isEffect{ isEffect_ }
{}
@ -158,10 +168,21 @@ CommandGroupItem::~CommandGroupItem() {}
SpecialItem::~SpecialItem() {}
CommandHandlerFinder FinderScope::sFinder =
[](AudacityProject &project) -> CommandHandlerObject & {
// If this default finder function is reached, then FinderScope should
// have been used somewhere, or an explicit CommandHandlerFinder passed
// to menu item constructors
wxASSERT( false );
return project;
};
}
namespace {
const auto MenuPathStart = wxT("MenuBar");
void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem );
void VisitItems(
@ -179,6 +200,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
@ -191,7 +218,7 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
else
if (const auto pCommand =
dynamic_cast<CommandItem*>( pItem )) {
manager.AddItem(
manager.AddItem( project,
pCommand->name, pCommand->label_in,
pCommand->finder, pCommand->callback,
pCommand->flags, pCommand->options
@ -226,7 +253,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 );
}
@ -251,45 +278,45 @@ void VisitItem( AudacityProject &project, MenuTable::BaseItem *pItem )
/// changes in configured preferences - for example changes in key-bindings
/// affect the short-cut key legend that appears beside each command,
MenuTable::BaseItemPtr FileMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr FileMenu();
MenuTable::BaseItemPtr EditMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr EditMenu();
MenuTable::BaseItemPtr SelectMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr SelectMenu();
MenuTable::BaseItemPtr ViewMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr ViewMenu();
MenuTable::BaseItemPtr TransportMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr TransportMenu();
MenuTable::BaseItemPtr TracksMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr TracksMenu();
MenuTable::BaseItemPtr GenerateMenu( AudacityProject& );
MenuTable::BaseItemPtr EffectMenu( AudacityProject& );
MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject& );
MenuTable::BaseItemPtr ToolsMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr GenerateMenu();
MenuTable::BaseItemSharedPtr EffectMenu();
MenuTable::BaseItemSharedPtr AnalyzeMenu();
MenuTable::BaseItemSharedPtr ToolsMenu();
MenuTable::BaseItemPtr WindowMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr WindowMenu();
MenuTable::BaseItemPtr ExtraMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr ExtraMenu();
MenuTable::BaseItemPtr HelpMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr HelpMenu();
// Table of menu factories.
// TODO: devise a registration system instead.
static const auto menuTree = MenuTable::Items(
FileMenu
, EditMenu
, SelectMenu
, ViewMenu
, TransportMenu
, TracksMenu
, GenerateMenu
, EffectMenu
, AnalyzeMenu
, ToolsMenu
, WindowMenu
, ExtraMenu
, HelpMenu
static const auto menuTree = MenuTable::Items( MenuPathStart
, FileMenu()
, EditMenu()
, SelectMenu()
, ViewMenu()
, TransportMenu()
, TracksMenu()
, GenerateMenu()
, EffectMenu()
, AnalyzeMenu()
, ToolsMenu()
, WindowMenu()
, ExtraMenu()
, HelpMenu()
);
void MenuCreator::CreateMenusAndCommands(AudacityProject &project)

View File

@ -499,7 +499,8 @@ void CommandManager::ClearCurrentMenu()
void CommandManager::AddItem(const CommandID &name,
void CommandManager::AddItem(AudacityProject &project,
const CommandID &name,
const TranslatableString &label_in,
CommandHandlerFinder finder,
CommandFunctorPointer callback,
@ -528,10 +529,10 @@ void CommandManager::AddItem(const CommandID &name,
SetCommandFlags(name, flags);
auto checkmark = options.check;
if (checkmark >= 0) {
auto &checker = options.checker;
if (checker) {
CurrentMenu()->AppendCheckItem(ID, label);
CurrentMenu()->Check(ID, checkmark != 0);
CurrentMenu()->Check(ID, checker( project ));
}
else {
CurrentMenu()->Append(ID, label);
@ -540,6 +541,12 @@ void CommandManager::AddItem(const CommandID &name,
mbSeparatorAllowed = true;
}
auto CommandManager::Options::MakeCheckFn(
const wxString key, bool defaultValue ) -> CheckFn
{
return [=](AudacityProject&){ return gPrefs->ReadBool( key, defaultValue ); };
}
///
/// Add a list of menu items to the current menu. When the user selects any
/// one of these, the given functor will be called

View File

@ -141,6 +141,9 @@ class AUDACITY_DLL_API CommandManager final
// For specifying unusual arguments in AddItem
struct Options
{
// type of a function that determines checkmark state
using CheckFn = std::function< bool(AudacityProject&) >;
Options() {}
// Allow implicit construction from an accelerator string, which is
// a very common case
@ -153,8 +156,6 @@ class AUDACITY_DLL_API CommandManager final
Options &&Accel (const wxChar *value) &&
{ accel = value; return std::move(*this); }
Options &&CheckState (bool value) &&
{ check = value ? 1 : 0; return std::move(*this); }
Options &&IsEffect (bool value = true) &&
{ bIsEffect = value; return std::move(*this); }
Options &&Parameter (const CommandParameter &value) &&
@ -168,14 +169,35 @@ class AUDACITY_DLL_API CommandManager final
Options &&AllowInMacros ( int value = 1 ) &&
{ allowInMacros = value; return std::move(*this); }
// Specify a constant check state
Options &&CheckState (bool value) && {
checker = value
? [](AudacityProject&){ return true; }
: [](AudacityProject&){ return false; }
;
return std::move(*this);
}
// CheckTest is overloaded
// Take arbitrary predicate
Options &&CheckTest (const CheckFn &fn) &&
{ checker = fn; return std::move(*this); }
// Take a preference path
Options &&CheckTest (const wxChar *key, bool defaultValue) && {
checker = MakeCheckFn( key, defaultValue );
return std::move(*this);
}
const wxChar *accel{ wxT("") };
int check{ -1 }; // default value means it's not a check item
CheckFn checker; // default value means it's not a check item
bool bIsEffect{ false };
CommandParameter parameter{};
TranslatableString longName{};
bool global{ false };
bool useStrictFlags{ false };
int allowInMacros{ -1 }; // 0 = never, 1 = always, -1 = deduce from label
private:
static CheckFn MakeCheckFn( const wxString key, bool defaultValue );
};
void AddItemList(const CommandID & name,
@ -186,7 +208,8 @@ class AUDACITY_DLL_API CommandManager final
CommandFlag flags,
bool bIsEffect = false);
void AddItem(const CommandID & name,
void AddItem(AudacityProject &project,
const CommandID & name,
const TranslatableString &label_in,
CommandHandlerFinder finder,
CommandFunctorPointer callback,
@ -382,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
@ -392,37 +416,72 @@ namespace MenuTable {
// large.
struct BaseItem {
// declare at least one virtual function so dynamic_cast will work
explicit
BaseItem( const Identifier &internalName )
: name{ internalName }
{}
virtual ~BaseItem();
const Identifier name;
};
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
// The name of the delegate is significant for path calculations
struct SharedItem final : BaseItem {
explicit SharedItem( const BaseItemSharedPtr &ptr_ )
: BaseItem{ wxEmptyString }
, 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
// The name of the substitute is significant for path calculations
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_ }
: BaseItem( wxEmptyString )
, factory{ factory_ }
{}
~ComputedItem() override;
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_ );
// Construction from an internal name and a previously built-up
// vector of pointers
GroupItem( const wxString &internalName, BaseItemPtrs &&items_ );
// In-line, variadic constructor that doesn't require building a vector
template< typename... Args >
GroupItem( Args&&... args )
GroupItem( const wxString &internalName, Args&&... args )
: BaseItem( internalName )
{ Append( std::forward< Args >( args )... ); }
~GroupItem() override;
~GroupItem() override = 0;
BaseItemPtrs items;
@ -450,18 +509,35 @@ 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
// TransparentGroupItem with an empty name is transparent to item path calculations
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_ );
// Construction from an internal name and a previously built-up
// vector of pointers
MenuItem( const wxString &internalName,
const TranslatableString &title_, BaseItemPtrs &&items_ );
// In-line, variadic constructor that doesn't require building a vector
template< typename... Args >
MenuItem(
MenuItem( const wxString &internalName,
const TranslatableString &title_, Args&&... args )
: GroupItem{ std::forward<Args>(args)... }
: GroupItem{ internalName, std::forward<Args>(args)... }
, title{ title_ }
{}
~MenuItem() override;
@ -469,15 +545,20 @@ 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() >;
// Construction from a previously built-up vector of pointers
ConditionalGroupItem( Condition condition_, BaseItemPtrs &&items_ );
// Construction from an internal name and a previously built-up
// vector of pointers
ConditionalGroupItem( const wxString &internalName,
Condition condition_, BaseItemPtrs &&items_ );
// In-line, variadic constructor that doesn't require building a vector
template< typename... Args >
ConditionalGroupItem( Condition condition_, Args&&... args )
: GroupItem{ std::forward<Args>(args)... }
ConditionalGroupItem( const wxString &internalName,
Condition condition_, Args&&... args )
: GroupItem{ internalName, std::forward<Args>(args)... }
, condition{ condition_ }
{}
~ConditionalGroupItem() override;
@ -485,21 +566,67 @@ namespace MenuTable {
Condition condition;
};
struct SeparatorItem final : BaseItem
// Describes a separator between menu items
struct SeparatorItem final : SingleItem
{
SeparatorItem() : SingleItem{ wxEmptyString } {}
~SeparatorItem() override;
};
struct CommandItem final : BaseItem {
// usage:
// auto scope = FinderScope( findCommandHandler );
// return Items( ... );
//
// or:
// return FinderScope( findCommandHandler )
// .Eval( Items( ... ) );
//
// where findCommandHandler names a function.
// This is used before a sequence of many calls to Command() and
// CommandGroup(), so that the finder argument need not be specified
// in each call.
class FinderScope : ValueRestorer< CommandHandlerFinder >
{
static CommandHandlerFinder sFinder;
public:
static CommandHandlerFinder DefaultFinder() { return sFinder; }
explicit
FinderScope( CommandHandlerFinder finder )
: ValueRestorer( sFinder, finder )
{}
// See usage comment above about this pass-through function
template< typename Value > Value&& Eval( Value &&value ) const
{ return std::forward<Value>(value); }
};
// Describes one command in a menu
struct CommandItem final : SingleItem {
CommandItem(const CommandID &name_,
const TranslatableString &label_in_,
CommandHandlerFinder finder_,
CommandFunctorPointer callback_,
CommandFlag flags_,
const CommandManager::Options &options_);
const CommandManager::Options &options_,
CommandHandlerFinder finder_);
// Takes a pointer to member function directly, and delegates to the
// previous constructor; useful within the lifetime of a FinderScope
template< typename Handler >
CommandItem(const CommandID &name_,
const TranslatableString &label_in_,
void (Handler::*pmf)(const CommandContext&),
CommandFlag flags_,
const CommandManager::Options &options_,
CommandHandlerFinder finder = FinderScope::DefaultFinder())
: CommandItem(name_, label_in_,
static_cast<CommandFunctorPointer>(pmf),
flags_, options_, finder)
{}
~CommandItem() override;
const CommandID name;
const TranslatableString label_in;
CommandHandlerFinder finder;
CommandFunctorPointer callback;
@ -507,16 +634,33 @@ 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_,
CommandHandlerFinder finder_,
CommandFunctorPointer callback_,
CommandFlag flags_,
bool isEffect_);
bool isEffect_,
CommandHandlerFinder finder_);
// Takes a pointer to member function directly, and delegates to the
// previous constructor; useful within the lifetime of a FinderScope
template< typename Handler >
CommandGroupItem(const wxString &name_,
std::initializer_list< ComponentInterfaceSymbol > items_,
void (Handler::*pmf)(const CommandContext&),
CommandFlag flags_,
bool isEffect_,
CommandHandlerFinder finder = FinderScope::DefaultFinder())
: CommandGroupItem(name_, items_,
static_cast<CommandFunctorPointer>(pmf),
flags_, isEffect_, finder)
{}
~CommandGroupItem() override;
const wxString name;
const std::vector<ComponentInterfaceSymbol> items;
CommandHandlerFinder finder;
CommandFunctorPointer callback;
@ -526,12 +670,13 @@ 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& ) >;
explicit SpecialItem( const Appender &fn_ )
: fn{ fn_ }
explicit SpecialItem( const wxString &internalName, const Appender &fn_ )
: SingleItem{ internalName }
, fn{ fn_ }
{}
~SpecialItem() override;
@ -543,76 +688,106 @@ namespace MenuTable {
// Group items can be constructed two ways.
// Pointers to subordinate items are moved into the result.
// Null pointers are permitted, and ignored when building the menu.
// Items are spliced into the enclosing menu
// Items are spliced into the enclosing menu.
// The name is untranslated and may be empty, to make the group transparent
// in identification of items by path. Otherwise try to keep the name
// stable across Audacity versions.
template< typename... Args >
inline BaseItemPtr Items( Args&&... args )
{ return std::make_unique<GroupItem>(
inline std::unique_ptr<TransparentGroupItem> Items(
const wxString &internalName, Args&&... args )
{ return std::make_unique<TransparentGroupItem>( internalName,
std::forward<Args>(args)... ); }
// Menu items can be constructed two ways, as for group items
// Items will appear in a main toolbar menu or in a sub-menu
// Items will appear in a main toolbar menu or in a sub-menu.
// The name is untranslated. Try to keep the name stable across Audacity
// versions.
// If the name of a menu is empty, then subordinate items cannot be located
// by path.
template< typename... Args >
inline BaseItemPtr Menu(
const TranslatableString &title, Args&&... args )
inline std::unique_ptr<MenuItem> Menu(
const wxString &internalName, const TranslatableString &title, Args&&... args )
{ return std::make_unique<MenuItem>(
title, std::forward<Args>(args)... ); }
inline BaseItemPtr Menu(
const TranslatableString &title, BaseItemPtrs &&items )
{ return std::make_unique<MenuItem>( title, std::move( items ) ); }
internalName, title, std::forward<Args>(args)... ); }
inline std::unique_ptr<MenuItem> Menu(
const wxString &internalName, const TranslatableString &title, BaseItemPtrs &&items )
{ return std::make_unique<MenuItem>(
internalName, title, std::move( items ) ); }
// Conditional group items can be constructed two ways, as for group items
// These items register in the CommandManager but are not shown in menus
// if the condition evaluates false.
// The name is untranslated. Try to keep the name stable across Audacity
// versions.
// Name for conditional group must be non-empty.
template< typename... Args >
inline BaseItemPtr ConditionalItems(
ConditionalGroupItem::Condition condition, Args&&... args )
inline std::unique_ptr<ConditionalGroupItem> ConditionalItems(
const wxString &internalName,
ConditionalGroupItem::Condition condition, Args&&... args )
{ return std::make_unique<ConditionalGroupItem>(
condition, std::forward<Args>(args)... ); }
inline BaseItemPtr ConditionalItems(
ConditionalGroupItem::Condition condition, BaseItemPtrs &&items )
internalName, condition, std::forward<Args>(args)... ); }
inline std::unique_ptr<ConditionalGroupItem> ConditionalItems(
const wxString &internalName, ConditionalGroupItem::Condition condition,
BaseItemPtrs &&items )
{ return std::make_unique<ConditionalGroupItem>(
condition, std::move( items ) ); }
internalName, condition, std::move( items ) ); }
// Make either a menu item or just a group, depending on the nonemptiness
// of the title
// of the title.
// The name is untranslated and may be empty, to make the group transparent
// in identification of items by path. Otherwise try to keep the name
// stable across Audacity versions.
// If the name of a menu is empty, then subordinate items cannot be located
// by path.
template< typename... Args >
inline BaseItemPtr MenuOrItems(
const TranslatableString &title, Args&&... args )
{ if ( title.empty() ) return Items( std::forward<Args>(args)... );
else return std::make_unique<MenuItem>(
title, std::forward<Args>(args)... ); }
const wxString &internalName, const TranslatableString &title, Args&&... args )
{ if ( title.empty() )
return Items( internalName, std::forward<Args>(args)... );
else
return std::make_unique<MenuItem>(
internalName, title, std::forward<Args>(args)... ); }
inline BaseItemPtr MenuOrItems(
const wxString &internalName,
const TranslatableString &title, BaseItemPtrs &&items )
{ if ( title.empty() ) return Items( std::move( items ) );
else return std::make_unique<MenuItem>( title, std::move( items ) ); }
{ if ( title.empty() )
return Items( internalName, std::move( items ) );
else
return std::make_unique<MenuItem>(
internalName, title, std::move( items ) ); }
inline std::unique_ptr<SeparatorItem> Separator()
{ return std::make_unique<SeparatorItem>(); }
template< typename Handler >
inline std::unique_ptr<CommandItem> Command(
const CommandID &name,
const TranslatableString &label_in,
CommandHandlerFinder finder, CommandFunctorPointer callback,
CommandFlag flags, const CommandManager::Options &options = {})
void (Handler::*pmf)(const CommandContext&),
CommandFlag flags, const CommandManager::Options &options = {},
CommandHandlerFinder finder = FinderScope::DefaultFinder())
{
return std::make_unique<CommandItem>(
name, label_in, finder, callback, flags, options
name, label_in, pmf, flags, options, finder
);
}
template< typename Handler >
inline std::unique_ptr<CommandGroupItem> CommandGroup(
const wxString &name,
std::initializer_list< ComponentInterfaceSymbol > items,
CommandHandlerFinder finder, CommandFunctorPointer callback,
CommandFlag flags, bool isEffect = false)
void (Handler::*pmf)(const CommandContext&),
CommandFlag flags, bool isEffect = false,
CommandHandlerFinder finder = FinderScope::DefaultFinder())
{
return std::make_unique<CommandGroupItem>(
name, items, finder, callback, flags, isEffect
name, items, pmf, flags, isEffect, finder
);
}
inline std::unique_ptr<SpecialItem> Special(
const SpecialItem::Appender &fn )
{ return std::make_unique<SpecialItem>( fn ); }
const wxString &name, const SpecialItem::Appender &fn )
{ return std::make_unique<SpecialItem>( name, fn ); }
}
#endif

View File

@ -821,15 +821,17 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& ClipActions::Handler :: X)
#define FN(X) (& ClipActions::Handler :: X)
MenuTable::BaseItemPtr ClipSelectMenu( AudacityProject& )
// Under /MenuBar/Select
MenuTable::BaseItemSharedPtr ClipSelectMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
return Menu( XO("Clip B&oundaries"),
static BaseItemSharedPtr menu {
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Clip"), XO("Clip B&oundaries"),
Command( wxT("SelPrevClipBoundaryToCursor"),
XXO("Pre&vious Clip Boundary to Cursor"),
FN(OnSelectPrevClipBoundaryToCursor),
@ -844,15 +846,19 @@ MenuTable::BaseItemPtr ClipSelectMenu( AudacityProject& )
Command( wxT("SelNextClip"), XXO("N&ext Clip"), FN(OnSelectNextClip),
WaveTracksExistFlag,
Options{ wxT("Alt+."), XO("Select Next Clip") } )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ClipCursorItems( AudacityProject & )
// Under /MenuBar/Transport/Cursor
MenuTable::BaseItemSharedPtr ClipCursorItems()
{
using namespace MenuTable;
using Options = CommandManager::Options;
return Items(
static BaseItemSharedPtr items{
FinderScope( findCommandHandler ).Eval(
Items( wxT("Clip"),
Command( wxT("CursPrevClipBoundary"), XXO("Pre&vious Clip Boundary"),
FN(OnCursorPrevClipBoundary),
WaveTracksExistFlag,
@ -861,19 +867,24 @@ MenuTable::BaseItemPtr ClipCursorItems( AudacityProject & )
FN(OnCursorNextClipBoundary),
WaveTracksExistFlag,
Options{}.LongName( XO("Cursor to Next Clip Boundary") ) )
);
) ) };
return items;
}
MenuTable::BaseItemPtr ExtraClipCursorItems( AudacityProject & )
// Under /MenuBar/Optional/Extra/Cursor
MenuTable::BaseItemSharedPtr ExtraClipCursorItems()
{
using namespace MenuTable;
return Items(
static BaseItemSharedPtr items{
FinderScope( findCommandHandler ).Eval(
Items( wxT("Clip"),
Command( wxT("ClipLeft"), XXO("Clip L&eft"), FN(OnClipLeft),
TracksExistFlag | TrackPanelHasFocus, wxT("\twantKeyup") ),
Command( wxT("ClipRight"), XXO("Clip Rig&ht"), FN(OnClipRight),
TracksExistFlag | TrackPanelHasFocus, wxT("\twantKeyup") )
);
) ) };
return items;
}
#undef FN

View File

@ -995,10 +995,9 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& EditActions::Handler :: X)
#define FN(X) (& EditActions::Handler :: X)
MenuTable::BaseItemPtr LabelEditMenus( AudacityProject &project );
MenuTable::BaseItemSharedPtr LabelEditMenus();
const ReservedCommandFlag
CutCopyAvailableFlag{
@ -1025,7 +1024,8 @@ const ReservedCommandFlag
cutCopyOptions()
};
MenuTable::BaseItemPtr EditMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr EditMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
@ -1052,14 +1052,17 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
#endif
;
return Menu( XO("&Edit"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Edit"), XO("&Edit"),
Command( wxT("Undo"), XXO("&Undo"), FN(OnUndo),
AudioIONotBusyFlag | UndoAvailableFlag, wxT("Ctrl+Z") ),
Command( wxT("Redo"), XXO("&Redo"), FN(OnRedo),
AudioIONotBusyFlag | RedoAvailableFlag, redoKey ),
Special( [](AudacityProject &project, wxMenu&) {
Special( wxT("UndoItemsUpdateStep"),
[](AudacityProject &project, wxMenu&) {
// Change names in the CommandManager as a side-effect
MenuManager::ModifyUndoMenuItems(project);
}),
@ -1086,7 +1089,7 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
Separator(),
Menu( XO("R&emove Special"),
Menu( wxT("RemoveSpecial"), XO("R&emove Special"),
/* i18n-hint: (verb) Do a special kind of cut*/
Command( wxT("SplitCut"), XXO("Spl&it Cut"), FN(OnSplitCut),
NotBusyTimeAndTracksFlags,
@ -1112,7 +1115,7 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
//////////////////////////////////////////////////////////////////////////
Menu( XO("Clip B&oundaries"),
Menu( wxT("Clip"), XO("Clip B&oundaries"),
/* i18n-hint: (verb) It's an item on a menu. */
Command( wxT("Split"), XXO("Sp&lit"), FN(OnSplit),
AudioIONotBusyFlag | WaveTracksSelectedFlag,
@ -1132,7 +1135,7 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
//////////////////////////////////////////////////////////////////////////
LabelEditMenus,
LabelEditMenus(),
Command( wxT("EditMetaData"), XXO("&Metadata..."), FN(OnEditMetadata),
AudioIONotBusyFlag ),
@ -1145,23 +1148,28 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
Command( wxT("Preferences"), XXO("Pre&ferences..."), FN(OnPreferences),
AudioIONotBusyFlag, prefKey )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraEditMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraEditMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
static const auto flags =
AudioIONotBusyFlag | TracksSelectedFlag | TimeSelectedFlag;
return Menu( XO("&Edit"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Edit"), XO("&Edit"),
Command( wxT("DeleteKey"), XXO("&Delete Key"), FN(OnDelete),
(flags | NoAutoSelect),
wxT("Backspace") ),
Command( wxT("DeleteKey2"), XXO("Delete Key&2"), FN(OnDelete),
(flags | NoAutoSelect),
wxT("Delete") )
);
) ) };
return menu;
}
auto canSelectAll = [](const AudacityProject &project){

View File

@ -134,66 +134,73 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& ExtraActions::Handler :: X)
#define FN(X) (& ExtraActions::Handler :: X)
// Imported menu item definitions
MenuTable::BaseItemPtr ExtraEditMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraSelectionMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraCursorMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraSeekMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraToolsMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraTransportMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraPlayAtSpeedMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraTrackMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraWindowItems( AudacityProject & );
MenuTable::BaseItemPtr ExtraGlobalCommands( AudacityProject & );
MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraMenu( AudacityProject& );
MenuTable::BaseItemPtr ExtraMixerMenu( AudacityProject & );
MenuTable::BaseItemPtr ExtraDeviceMenu( AudacityProject & );
MenuTable::BaseItemSharedPtr ExtraEditMenu();
MenuTable::BaseItemSharedPtr ExtraSelectionMenu();
MenuTable::BaseItemSharedPtr ExtraCursorMenu();
MenuTable::BaseItemSharedPtr ExtraSeekMenu();
MenuTable::BaseItemSharedPtr ExtraToolsMenu();
MenuTable::BaseItemSharedPtr ExtraTransportMenu();
MenuTable::BaseItemSharedPtr ExtraPlayAtSpeedMenu();
MenuTable::BaseItemSharedPtr ExtraTrackMenu();
MenuTable::BaseItemSharedPtr ExtraScriptablesIMenu();
MenuTable::BaseItemSharedPtr ExtraScriptablesIIMenu();
MenuTable::BaseItemSharedPtr ExtraWindowItems();
MenuTable::BaseItemSharedPtr ExtraGlobalCommands();
MenuTable::BaseItemSharedPtr ExtraFocusMenu();
MenuTable::BaseItemSharedPtr ExtraMenu();
MenuTable::BaseItemSharedPtr ExtraMixerMenu();
MenuTable::BaseItemSharedPtr ExtraDeviceMenu();
MenuTable::BaseItemPtr ExtraMiscItems( AudacityProject & );
// Table of menu factories.
// TODO: devise a registration system instead.
static const std::shared_ptr<MenuTable::BaseItem> extraItems = MenuTable::Items(
ExtraTransportMenu
, ExtraToolsMenu
, ExtraMixerMenu
, ExtraEditMenu
, ExtraPlayAtSpeedMenu
, ExtraSeekMenu
, ExtraDeviceMenu
, ExtraSelectionMenu
, MenuTable::Separator()
, ExtraGlobalCommands
, ExtraFocusMenu
, ExtraCursorMenu
, ExtraTrackMenu
, ExtraScriptablesIMenu
, ExtraScriptablesIIMenu
, ExtraMiscItems
);
MenuTable::BaseItemPtr ExtraMenu( AudacityProject & )
MenuTable::BaseItemSharedPtr ExtraMenu()
{
using namespace MenuTable;
// Table of menu factories.
// TODO: devise a registration system instead.
static BaseItemSharedPtr extraItems{ Items( wxEmptyString
, ExtraTransportMenu()
, ExtraToolsMenu()
, ExtraMixerMenu()
, ExtraEditMenu()
, ExtraPlayAtSpeedMenu()
, ExtraSeekMenu()
, ExtraDeviceMenu()
, ExtraSelectionMenu()
, MenuTable::Separator()
, ExtraGlobalCommands()
, ExtraFocusMenu()
, ExtraCursorMenu()
, ExtraTrackMenu()
, ExtraScriptablesIMenu()
, ExtraScriptablesIIMenu()
// Delayed evaluation:
, ExtraMiscItems
) };
static const auto pred =
[]{ return gPrefs->ReadBool(wxT("/GUI/ShowExtraMenus"), false); };
static const auto factory =
[](AudacityProject &){ return extraItems; };
return ConditionalItems( pred, Menu( XO("Ext&ra"), factory ) );
static BaseItemSharedPtr menu{
ConditionalItems( wxT("Optional"),
pred, Menu( wxT("Extra"), XO("Ext&ra"), extraItems ) )
};
return menu;
}
MenuTable::BaseItemPtr ExtraMixerMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraMixerMenu()
{
using namespace MenuTable;
return Menu( XO("Mi&xer"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Mixer"), XO("Mi&xer"),
Command( wxT("OutputGain"), XXO("Ad&just Playback Volume..."),
FN(OnOutputGain), AlwaysEnabledFlag ),
Command( wxT("OutputGainInc"), XXO("&Increase Playback Volume"),
@ -206,13 +213,17 @@ MenuTable::BaseItemPtr ExtraMixerMenu( AudacityProject & )
FN(OnInputGainInc), AlwaysEnabledFlag ),
Command( wxT("InputGainDec"), XXO("D&ecrease Recording Volume"),
FN(OnInputGainDec), AlwaysEnabledFlag )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraDeviceMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraDeviceMenu()
{
using namespace MenuTable;
return Menu( XO("De&vice"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Device"), XO("De&vice"),
Command( wxT("InputDevice"), XXO("Change &Recording Device..."),
FN(OnInputDevice),
AudioIONotBusyFlag, wxT("Shift+I") ),
@ -224,9 +235,11 @@ MenuTable::BaseItemPtr ExtraDeviceMenu( AudacityProject & )
Command( wxT("InputChannels"), XXO("Change Recording Cha&nnels..."),
FN(OnInputChannels),
AudioIONotBusyFlag, wxT("Shift+N") )
);
) ) };
return menu;
}
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemPtr ExtraMiscItems( AudacityProject &project )
{
using namespace MenuTable;
@ -241,7 +254,8 @@ MenuTable::BaseItemPtr ExtraMiscItems( AudacityProject &project )
;
// Not a menu.
return Items(
return FinderScope( findCommandHandler ).Eval(
Items( wxT("Misc"),
// Accel key is not bindable.
Command( wxT("FullScreenOnOff"), XXO("&Full Screen (on/off)"),
FN(OnFullScreen),
@ -249,8 +263,8 @@ MenuTable::BaseItemPtr ExtraMiscItems( AudacityProject &project )
Options{ key }.CheckState(
GetProjectFrame( project ).wxTopLevelWindow::IsFullScreen() ) ),
ExtraWindowItems
);
ExtraWindowItems()
) );
}
#undef FN

View File

@ -549,15 +549,17 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& FileActions::Handler :: X)
#define FN(X) (& FileActions::Handler :: X)
MenuTable::BaseItemPtr FileMenu( AudacityProject& )
// under /MenuBar
MenuTable::BaseItemSharedPtr FileMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
return Menu( XO("&File"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("File"), XO("&File"),
/*i18n-hint: "New" is an action (verb) to create a NEW project*/
Command( wxT("New"), XXO("&New"), FN(OnNew),
AudioIONotBusyFlag, wxT("Ctrl+N") ),
@ -577,7 +579,7 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
/////////////////////////////////////////////////////////////////////////////
Menu(
Menu( wxT("Recent"),
#ifdef __WXMAC__
/* i18n-hint: This is the name of the menu item on Mac OS X only */
XO("Open Recent")
@ -586,7 +588,8 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
XO("Recent &Files")
#endif
,
Special( [](AudacityProject &, wxMenu &theMenu){
Special( wxT("PopulateRecentFilesStep"),
[](AudacityProject &, wxMenu &theMenu){
// Recent Files and Recent Projects menus
auto &history = FileHistory::Global();
history.UseMenu( &theMenu );
@ -615,7 +618,7 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
Separator(),
Menu( XO("&Save Project"),
Menu( wxT("Save"), XO("&Save Project"),
Command( wxT("Save"), XXO("&Save Project"), FN(OnSave),
AudioIONotBusyFlag | UnsavedChangesFlag, wxT("Ctrl+S") ),
Command( wxT("SaveAs"), XXO("Save Project &As..."), FN(OnSaveAs),
@ -633,7 +636,7 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
Separator(),
Menu( XO("&Export"),
Menu( wxT("Export"), XO("&Export"),
// Enable Export audio commands only when there are audio tracks.
Command( wxT("ExportMp3"), XXO("Export as MP&3"), FN(OnExportMp3),
AudioIONotBusyFlag | WaveTracksExistFlag ),
@ -667,7 +670,7 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
#endif
),
Menu( XO("&Import"),
Menu( wxT("Import"), XO("&Import"),
Command( wxT("ImportAudio"), XXO("&Audio..."), FN(OnImport),
AudioIONotBusyFlag, wxT("Ctrl+Shift+I") ),
Command( wxT("ImportLabels"), XXO("&Labels..."), FN(OnImportLabels),
@ -698,7 +701,8 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
/* i18n-hint: (verb) It's item on a menu. */
Command( wxT("Exit"), XXO("E&xit"), FN(OnExit),
AlwaysEnabledFlag, wxT("Ctrl+Q") )
);
) ) };
return menu;
}
#undef FN

View File

@ -418,18 +418,15 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& HelpActions::Handler :: X)
#define FN(X) (& HelpActions::Handler :: X)
MenuTable::BaseItemPtr HelpMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr HelpMenu()
{
#ifdef __WXMAC__
wxApp::s_macHelpMenuTitleName = _("&Help");
#endif
using namespace MenuTable;
return Menu( XO("&Help"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Help"), XO("&Help"),
// QuickFix menu item not in Audacity 2.3.1 whilst we discuss further.
#ifdef EXPERIMENTAL_DA
// DA: Has QuickFix menu item.
@ -448,7 +445,7 @@ MenuTable::BaseItemPtr HelpMenu( AudacityProject & )
Separator(),
Menu( XO("&Diagnostics"),
Menu( wxT("Diagnostics"), XO("&Diagnostics"),
Command( wxT("DeviceInfo"), XXO("Au&dio Device Info..."),
FN(OnAudioDeviceInfo),
AudioIONotBusyFlag ),
@ -480,7 +477,8 @@ MenuTable::BaseItemPtr HelpMenu( AudacityProject & )
#endif
Command( wxT("About"), XXO("&About Audacity..."), FN(OnAbout),
AlwaysEnabledFlag )
);
) ) };
return menu;
}
#undef FN

View File

@ -559,10 +559,10 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& LabelEditActions::Handler :: X)
#define FN(X) (& LabelEditActions::Handler :: X)
MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & )
// Under /MenuBar/Edit
MenuTable::BaseItemSharedPtr LabelEditMenus()
{
using namespace MenuTable;
using Options = CommandManager::Options;
@ -575,9 +575,11 @@ MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & )
// Returns TWO menus.
return Items(
Menu( XO("&Labels"),
static BaseItemSharedPtr menus{
FinderScope( findCommandHandler ).Eval(
Items( wxEmptyString,
Menu( wxT("Labels"), XO("&Labels"),
Command( wxT("EditLabels"), XXO("&Edit Labels..."), FN(OnEditLabels),
AudioIONotBusyFlag ),
@ -607,7 +609,7 @@ MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & )
/////////////////////////////////////////////////////////////////////////////
Menu( XO("La&beled Audio"),
Menu( wxT("Labeled"), XO("La&beled Audio"),
/* i18n-hint: (verb)*/
Command( wxT("CutLabels"), XXO("&Cut"), FN(OnCutLabels),
AudioIONotBusyFlag | LabelsSelectedFlag | WaveTracksExistFlag |
@ -653,7 +655,8 @@ MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & )
wxT("Alt+Shift+J") )
) // second menu
); // two menus
) ) }; // two menus
return menus;
}
#undef FN

View File

@ -553,30 +553,37 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &project) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& NavigationActions::Handler :: X)
#define FN(X) (& NavigationActions::Handler :: X)
MenuTable::BaseItemPtr ExtraGlobalCommands( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraGlobalCommands()
{
// Ceci n'est pas un menu
using namespace MenuTable;
using Options = CommandManager::Options;
return Items(
static BaseItemSharedPtr items{
FinderScope( findCommandHandler ).Eval(
Items( wxT("Navigation"),
Command( wxT("PrevWindow"), XXO("Move Backward Through Active Windows"),
FN(OnPrevWindow), AlwaysEnabledFlag,
Options{ wxT("Alt+Shift+F6") }.IsGlobal() ),
Command( wxT("NextWindow"), XXO("Move Forward Through Active Windows"),
FN(OnNextWindow), AlwaysEnabledFlag,
Options{ wxT("Alt+F6") }.IsGlobal() )
);
) ) };
return items;
}
MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraFocusMenu()
{
using namespace MenuTable;
static const auto FocusedTracksFlags = TracksExistFlag | TrackPanelHasFocus;
return Menu( XO("F&ocus"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Focus"), XO("F&ocus"),
Command( wxT("PrevFrame"),
XXO("Move &Backward from Toolbars to Tracks"), FN(OnPrevFrame),
AlwaysEnabledFlag, wxT("Ctrl+Shift+F6") ),
@ -599,7 +606,8 @@ MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & )
FocusedTracksFlags, wxT("Return") ),
Command( wxT("ToggleAlt"), XXO("Toggle Focuse&d Track"), FN(OnToggle),
FocusedTracksFlags, wxT("NUMPAD_ENTER") )
);
) ) };
return menu;
}
#undef FN

View File

@ -258,7 +258,7 @@ void AddEffectMenuItems(
groupNames,
groupPlugs, groupFlags, isDefault);
table.push_back( MenuOrItems(
table.push_back( MenuOrItems( wxEmptyString,
( bInSubmenu ? last : TranslatableString{} ), std::move( temp )
) );
@ -283,7 +283,7 @@ void AddEffectMenuItems(
AddEffectMenuItemGroup(temp,
groupNames, groupPlugs, groupFlags, isDefault);
table.push_back( MenuOrItems(
table.push_back( MenuOrItems( wxEmptyString,
( bInSubmenu ? current : TranslatableString{} ), std::move( temp )
) );
}
@ -585,8 +585,7 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions? ...
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& PluginActions::Handler :: X)
#define FN(X) (& PluginActions::Handler :: X)
// ... buf first some more helper definitions, which use FN
namespace {
@ -632,6 +631,8 @@ void AddEffectMenuItemGroup(
}
using namespace MenuTable;
// This finder scope may be redundant, but harmless
auto scope = FinderScope( findCommandHandler );
auto pTable = &table;
BaseItemPtrs temp1;
@ -666,7 +667,7 @@ void AddEffectMenuItemGroup(
i++;
}
pTable->push_back( Menu( name, std::move( temp2 ) ) );
pTable->push_back( Menu( wxEmptyString, name, std::move( temp2 ) ) );
i--;
}
else
@ -701,7 +702,7 @@ void AddEffectMenuItemGroup(
end = groupCnt;
}
// Done collecting
table.push_back( Menu(
table.push_back( Menu( wxEmptyString,
XO("Plug-in %d to %d").Format( groupNdx + 1, end ),
std::move( temp1 )
) );
@ -721,6 +722,8 @@ MenuTable::BaseItemPtrs PopulateMacrosMenu( CommandFlag flags )
auto names = MacroCommands::GetNames(); // these names come from filenames
int i;
// This finder scope may be redundant, but harmless
auto scope = MenuTable::FinderScope( findCommandHandler );
for (i = 0; i < (int)names.size(); i++) {
auto MacroID = ApplyMacroDialog::MacroIdOfName( names[i] );
result.push_back( MenuTable::Command( MacroID,
@ -738,13 +741,16 @@ MenuTable::BaseItemPtrs PopulateMacrosMenu( CommandFlag flags )
// Menu definitions
MenuTable::BaseItemPtr GenerateMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr GenerateMenu()
{
using namespace MenuTable;
// All of this is a bit hacky until we can get more things connected into
// the plugin manager...sorry! :-(
return Menu( XO("&Generate"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Generate"), XO("&Generate"),
#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT
Command( wxT("ManageGenerators"), XXO("Add / Remove Plug-ins..."),
FN(OnManageGenerators), AudioIONotBusyFlag ),
@ -753,11 +759,15 @@ MenuTable::BaseItemPtr GenerateMenu( AudacityProject & )
#endif
Items( PopulateEffectsMenu(
// Delayed evaluation:
[](AudacityProject &)
{ return Items( wxEmptyString, PopulateEffectsMenu(
EffectTypeGenerate,
AudioIONotBusyFlag,
AudioIONotBusyFlag) )
);
AudioIONotBusyFlag)
); }
) ) };
return menu;
}
const ReservedCommandFlag
@ -767,21 +777,16 @@ const ReservedCommandFlag
}
}; //lll
MenuTable::BaseItemPtr EffectMenu( AudacityProject &project )
// Under /MenuBar
MenuTable::BaseItemSharedPtr EffectMenu()
{
using namespace MenuTable;
// All of this is a bit hacky until we can get more things connected into
// the plugin manager...sorry! :-(
const auto &lastEffect = MenuManager::Get(project).mLastEffect;
TranslatableString buildMenuLabel;
if (!lastEffect.empty())
buildMenuLabel = XO("Repeat %s")
.Format( EffectManager::Get().GetCommandName(lastEffect) );
else
buildMenuLabel = XO("Repeat Last Effect");
return Menu( XO("Effe&ct"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Effect"), XO("Effe&ct"),
#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT
Command( wxT("ManageEffects"), XXO("Add / Remove Plug-ins..."),
FN(OnManageEffects), AudioIONotBusyFlag ),
@ -789,28 +794,49 @@ MenuTable::BaseItemPtr EffectMenu( AudacityProject &project )
Separator(),
#endif
Command( wxT("RepeatLastEffect"), buildMenuLabel,
FN(OnRepeatLastEffect),
AudioIONotBusyFlag | TimeSelectedFlag |
WaveTracksSelectedFlag | HasLastEffectFlag,
wxT("Ctrl+R") ),
// Delayed evaluation:
[](AudacityProject &project)
{
const auto &lastEffect = MenuManager::Get(project).mLastEffect;
TranslatableString buildMenuLabel;
if (!lastEffect.empty())
buildMenuLabel = XO("Repeat %s")
.Format( EffectManager::Get().GetCommandName(lastEffect) );
else
buildMenuLabel = XO("Repeat Last Effect");
return Command( wxT("RepeatLastEffect"), buildMenuLabel,
FN(OnRepeatLastEffect),
AudioIONotBusyFlag | TimeSelectedFlag |
WaveTracksSelectedFlag | HasLastEffectFlag,
wxT("Ctrl+R"), findCommandHandler );
},
Separator(),
Items( PopulateEffectsMenu(
// Delayed evaluation:
[](AudacityProject &)
{ return Items( wxEmptyString, PopulateEffectsMenu(
EffectTypeProcess,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
IsRealtimeNotActiveFlag ) )
);
IsRealtimeNotActiveFlag )
); }
) ) };
return menu;
}
MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr AnalyzeMenu()
{
using namespace MenuTable;
// All of this is a bit hacky until we can get more things connected into
// the plugin manager...sorry! :-(
return Menu( XO("&Analyze"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Analyze"), XO("&Analyze"),
#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT
Command( wxT("ManageAnalyzers"), XXO("Add / Remove Plug-ins..."),
FN(OnManageAnalyzers), AudioIONotBusyFlag ),
@ -825,20 +851,26 @@ MenuTable::BaseItemPtr AnalyzeMenu( AudacityProject & )
Command( wxT("PlotSpectrum"), XXO("Plot Spectrum..."), FN(OnPlotSpectrum),
AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag ),
Items( PopulateEffectsMenu(
// Delayed evaluation:
[](AudacityProject&)
{ return Items( wxEmptyString, PopulateEffectsMenu(
EffectTypeAnalyze,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
IsRealtimeNotActiveFlag ) )
);
IsRealtimeNotActiveFlag )
); }
) ) };
return menu;
}
MenuTable::BaseItemPtr ToolsMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr ToolsMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
auto gAudioIO = AudioIO::Get();
return Menu( XO("T&ools"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Tools"), XO("T&ools"),
#ifdef EXPERIMENTAL_EFFECT_MANAGEMENT
Command( wxT("ManageTools"), XXO("Add / Remove Plug-ins..."),
@ -851,7 +883,7 @@ MenuTable::BaseItemPtr ToolsMenu( AudacityProject & )
Command( wxT("ManageMacros"), XXO("&Macros..."),
FN(OnManageMacros), AudioIONotBusyFlag ),
Menu( XO("&Apply Macro"),
Menu( wxT("Macros"), XO("&Apply Macro"),
// Palette has no access key to ensure first letter navigation of
// sub menu
Command( wxT("ApplyMacrosPalette"), XXO("Palette..."),
@ -859,7 +891,9 @@ MenuTable::BaseItemPtr ToolsMenu( AudacityProject & )
Separator(),
Items( PopulateMacrosMenu( AudioIONotBusyFlag ) )
// Delayed evaluation:
[](AudacityProject&)
{ return Items( wxEmptyString, PopulateMacrosMenu( AudioIONotBusyFlag ) ); }
),
Separator(),
@ -878,10 +912,13 @@ MenuTable::BaseItemPtr ToolsMenu( AudacityProject & )
Separator(),
Items( PopulateEffectsMenu(
// Delayed evaluation:
[](AudacityProject&)
{ return Items( wxEmptyString, PopulateEffectsMenu(
EffectTypeTool,
AudioIONotBusyFlag,
AudioIONotBusyFlag ) )
AudioIONotBusyFlag )
); }
#ifdef IS_ALPHA
,
@ -892,23 +929,31 @@ MenuTable::BaseItemPtr ToolsMenu( AudacityProject & )
XXO("Simulate Recording Errors"),
FN(OnSimulateRecordingErrors),
AudioIONotBusyFlag,
Options{}.CheckState( gAudioIO->mSimulateRecordingErrors ) ),
Options{}.CheckTest(
[](AudacityProject&){
return AudioIO::Get()->mSimulateRecordingErrors; } ) ),
Command( wxT("DetectUpstreamDropouts"),
XXO("Detect Upstream Dropouts"),
FN(OnDetectUpstreamDropouts),
AudioIONotBusyFlag,
Options{}.CheckState( gAudioIO->mDetectUpstreamDropouts ) )
Options{}.CheckTest(
[](AudacityProject&){
return AudioIO::Get()->mDetectUpstreamDropouts; } ) )
#endif
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraScriptablesIMenu()
{
using namespace MenuTable;
// These are the more useful to VI user Scriptables.
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
// i18n-hint: Scriptables are commands normally used from Python, Perl etc.
return Menu( XO("Script&ables I"),
Menu( wxT("Scriptables1"), XO("Script&ables I"),
// Note that the PLUGIN_SYMBOL must have a space between words,
// whereas the short-form used here must not.
// (So if you did write "CompareAudio" for the PLUGIN_SYMBOL name, then
@ -945,15 +990,19 @@ MenuTable::BaseItemPtr ExtraScriptablesIMenu( AudacityProject & )
AudioIONotBusyFlag ),
Command( wxT("SetProject"), XXO("Set Project..."), FN(OnAudacityCommand),
AudioIONotBusyFlag )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraScriptablesIIMenu()
{
using namespace MenuTable;
// Less useful to VI users.
return Menu( XO("Scripta&bles II"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Scriptables2"), XO("Scripta&bles II"),
Command( wxT("Select"), XXO("Select..."), FN(OnAudacityCommand),
AudioIONotBusyFlag ),
Command( wxT("SetTrack"), XXO("Set Track..."), FN(OnAudacityCommand),
@ -983,7 +1032,8 @@ MenuTable::BaseItemPtr ExtraScriptablesIIMenu( AudacityProject & )
Command( wxT("Screenshot"), XXO("Screenshot (short format)..."),
FN(OnAudacityCommand),
AudioIONotBusyFlag )
);
) ) };
return menu;
}
#undef FN

View File

@ -1026,18 +1026,19 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &project) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& SelectActions::Handler :: X)
#define FN(X) (& SelectActions::Handler :: X)
MenuTable::BaseItemPtr ClipSelectMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr ClipSelectMenu();
MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
// Under /MenuBar
MenuTable::BaseItemSharedPtr SelectMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
/* i18n-hint: (verb) It's an item on a menu. */
return Menu( XO("&Select"),
Menu( wxT("Select"), XO("&Select"),
Command( wxT("SelectAll"), XXO("&All"), FN(OnSelectAll),
TracksExistFlag,
Options{ wxT("Ctrl+A"), XO("Select All") } ),
@ -1047,7 +1048,7 @@ MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
//////////////////////////////////////////////////////////////////////////
Menu( XO("&Tracks"),
Menu( wxT("Tracks"), XO("&Tracks"),
Command( wxT("SelAllTracks"), XXO("In All &Tracks"),
FN(OnSelectAllTracks),
TracksExistFlag,
@ -1064,7 +1065,7 @@ MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
//////////////////////////////////////////////////////////////////////////
Menu( XO("R&egion"),
Menu( wxT("Region"), XO("R&egion"),
Command( wxT("SetLeftSelection"), XXO("&Left at Playback Position"),
FN(OnSetLeftSelection), TracksExistFlag,
Options{ wxT("["), XO("Set Selection Left at Play Position") } ),
@ -1098,7 +1099,7 @@ MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
//////////////////////////////////////////////////////////////////////////
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
Menu( XO("S&pectral"),
Menu( wxT("Spectral"), XO("S&pectral"),
Command( wxT("ToggleSpectralSelection"),
XXO("To&ggle Spectral Selection"), FN(OnToggleSpectralSelection),
TracksExistFlag, wxT("Q") ),
@ -1113,7 +1114,7 @@ MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
//////////////////////////////////////////////////////////////////////////
ClipSelectMenu,
ClipSelectMenu(),
//////////////////////////////////////////////////////////////////////////
@ -1135,13 +1136,17 @@ MenuTable::BaseItemPtr SelectMenu( AudacityProject& )
Command( wxT("ZeroCross"), XXO("At &Zero Crossings"),
FN(OnZeroCrossing), TracksSelectedFlag,
Options{ wxT("Z"), XO("Select Zero Crossing") } )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraSelectionMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraSelectionMenu()
{
using namespace MenuTable;
return Menu( XO("&Selection"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Select"), XO("&Selection"),
Command( wxT("SnapToOff"), XXO("Snap-To &Off"), FN(OnSnapToOff),
AlwaysEnabledFlag ),
Command( wxT("SnapToNearest"), XXO("Snap-To &Nearest"),
@ -1174,12 +1179,14 @@ MenuTable::BaseItemPtr ExtraSelectionMenu( AudacityProject & )
FN(OnSelContractRight),
TracksExistFlag | TrackPanelHasFocus,
wxT("Ctrl+Shift+Left\twantKeyup") )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ClipCursorItems( AudacityProject & );
MenuTable::BaseItemSharedPtr ClipCursorItems();
MenuTable::BaseItemPtr CursorMenu( AudacityProject & )
// Under /MenuBar/Transport
MenuTable::BaseItemSharedPtr CursorMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
@ -1190,7 +1197,9 @@ MenuTable::BaseItemPtr CursorMenu( AudacityProject & )
// GA: 'Skip to' moves the viewpoint to center of the track and preserves the
// selection. 'Cursor to' does neither. 'Center at' might describe it better
// than 'Skip'.
return Menu( XO("&Cursor to"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Cursor"), XO("&Cursor to"),
Command( wxT("CursSelStart"), XXO("Selection Star&t"),
FN(OnCursorSelStart),
TimeSelectedFlag,
@ -1209,7 +1218,7 @@ MenuTable::BaseItemPtr CursorMenu( AudacityProject & )
TracksSelectedFlag,
Options{ wxT("K"), XO("Cursor to Track End") } ),
ClipCursorItems,
ClipCursorItems(),
Command( wxT("CursProjectStart"), XXO("&Project Start"),
FN(OnSkipStart),
@ -1218,16 +1227,20 @@ MenuTable::BaseItemPtr CursorMenu( AudacityProject & )
Command( wxT("CursProjectEnd"), XXO("Project E&nd"), FN(OnSkipEnd),
CanStopFlags,
Options{ wxT("End"), XO("Cursor to Project End") } )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraClipCursorItems( AudacityProject & );
MenuTable::BaseItemSharedPtr ExtraClipCursorItems();
MenuTable::BaseItemPtr ExtraCursorMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraCursorMenu()
{
using namespace MenuTable;
return Menu( XO("&Cursor"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Cursor"), XO("&Cursor"),
Command( wxT("CursorLeft"), XXO("Cursor &Left"), FN(OnCursorLeft),
TracksExistFlag | TrackPanelHasFocus,
wxT("Left\twantKeyup\tallowDup") ),
@ -1247,14 +1260,18 @@ MenuTable::BaseItemPtr ExtraCursorMenu( AudacityProject & )
FN(OnCursorLongJumpRight),
TracksExistFlag | TrackPanelHasFocus, wxT("Shift+.") ),
ExtraClipCursorItems
);
ExtraClipCursorItems()
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraSeekMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraSeekMenu()
{
using namespace MenuTable;
return Menu( XO("See&k"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Seek"), XO("See&k"),
Command( wxT("SeekLeftShort"), XXO("Short Seek &Left During Playback"),
FN(OnSeekLeftShort), AudioIOBusyFlag, wxT("Left\tallowDup") ),
Command( wxT("SeekRightShort"),
@ -1264,7 +1281,8 @@ MenuTable::BaseItemPtr ExtraSeekMenu( AudacityProject & )
FN(OnSeekLeftLong), AudioIOBusyFlag, wxT("Shift+Left\tallowDup") ),
Command( wxT("SeekRightLong"), XXO("Long Seek Rig&ht During Playback"),
FN(OnSeekRightLong), AudioIOBusyFlag, wxT("Shift+Right\tallowDup") )
);
) ) };
return menu;
}
#undef FN

View File

@ -251,17 +251,19 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& ToolbarActions::Handler :: X)
#define FN(X) (& ToolbarActions::Handler :: X)
MenuTable::BaseItemPtr ToolbarsMenu( AudacityProject& )
// Under /MenuBar/View
MenuTable::BaseItemSharedPtr ToolbarsMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
static const auto checkOff = Options{}.CheckState( false );
return Menu( XO("&Toolbars"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Toolbars"), XO("&Toolbars"),
/* i18n-hint: (verb)*/
Command( wxT("ResetToolbars"), XXO("Reset Toolb&ars"),
FN(OnResetToolBars), AlwaysEnabledFlag ),
@ -330,13 +332,17 @@ MenuTable::BaseItemPtr ToolbarsMenu( AudacityProject& )
XXO("Spe&ctral Selection Toolbar"),
FN(OnShowSpectralSelectionToolBar), AlwaysEnabledFlag, checkOff )
#endif
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraToolsMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraToolsMenu()
{
using namespace MenuTable;
return Menu( XO("T&ools"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Tools"), XO("T&ools"),
Command( wxT("SelectTool"), XXO("&Selection Tool"), FN(OnSelectTool),
AlwaysEnabledFlag, wxT("F1") ),
Command( wxT("EnvelopeTool"), XXO("&Envelope Tool"),
@ -353,7 +359,8 @@ MenuTable::BaseItemPtr ExtraToolsMenu( AudacityProject & )
AlwaysEnabledFlag, wxT("A") ),
Command( wxT("NextTool"), XXO("&Next Tool"), FN(OnNextTool),
AlwaysEnabledFlag, wxT("D") )
);
) ) };
return menu;
}
#undef FN

View File

@ -1274,17 +1274,19 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& TrackActions::Handler :: X)
#define FN(X) (& TrackActions::Handler :: X)
MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr TracksMenu()
{
// Tracks Menu (formerly Project Menu)
using namespace MenuTable;
using Options = CommandManager::Options;
return Menu( XO("&Tracks"),
Menu( XO("Add &New"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Tracks"), XO("&Tracks"),
Menu( wxT("Add"), XO("Add &New"),
Command( wxT("NewMonoTrack"), XXO("&Mono Track"), FN(OnNewWaveTrack),
AudioIONotBusyFlag, wxT("Ctrl+Shift+N") ),
Command( wxT("NewStereoTrack"), XXO("&Stereo Track"),
@ -1299,7 +1301,8 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
Separator(),
Menu( XO("Mi&x"),
Menu( wxT("Mix"), XO("Mi&x"),
// Delayed evaluation
// Stereo to Mono is an oddball command that is also subject to control
// by the plug-in manager, as if an effect. Decide whether to show or
// hide it.
@ -1311,7 +1314,7 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
return Command( wxT("Stereo to Mono"),
XXO("Mix Stereo Down to &Mono"), FN(OnStereoToMono),
AudioIONotBusyFlag | StereoRequiredFlag |
WaveTracksSelectedFlag );
WaveTracksSelectedFlag, Options{}, findCommandHandler );
else
return {};
},
@ -1334,14 +1337,14 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
Separator(),
Menu( XO("M&ute/Unmute"),
Menu( wxT("Mute"), XO("M&ute/Unmute"),
Command( wxT("MuteAllTracks"), XXO("&Mute All Tracks"),
FN(OnMuteAllTracks), AudioIONotBusyFlag, wxT("Ctrl+U") ),
Command( wxT("UnmuteAllTracks"), XXO("&Unmute All Tracks"),
FN(OnUnmuteAllTracks), AudioIONotBusyFlag, wxT("Ctrl+Shift+U") )
),
Menu( XO("&Pan"),
Menu( wxT("Pan"), XO("&Pan"),
// As Pan changes are not saved on Undo stack,
// pan settings for all tracks
// in the project could very easily be lost unless we
@ -1361,7 +1364,7 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
//////////////////////////////////////////////////////////////////////////
Menu( XO("&Align Tracks"), // XO("Just Move Tracks"),
Menu( wxT("Align"), XO("&Align Tracks"), // XO("Just Move Tracks"),
// Mutual alignment of tracks independent of selection or zero
CommandGroup(wxT("Align"),
{
@ -1372,7 +1375,7 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
Separator(),
// Alignment commands using selection or zero
// Alignment commands using selection or zero
CommandGroup(wxT("Align"),
alignLabels,
FN(OnAlign), AudioIONotBusyFlag | TracksSelectedFlag),
@ -1383,14 +1386,13 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
XXO("&Move Selection with Tracks (on/off)"),
FN(OnMoveSelectionWithTracks),
AlwaysEnabledFlag,
Options{}.CheckState(
gPrefs->Read(wxT("/GUI/MoveSelectionWithTracks"), 0L ) ) )
Options{}.CheckTest( wxT("/GUI/MoveSelectionWithTracks"), false ) )
),
#if 0
// TODO: Can these labels be made clearer?
// Do we need this sub-menu at all?
Menu( XO("Move Sele&ction and Tracks"), {
Menu( wxT("MoveSelectionAndTracks"), XO("Move Sele&ction and Tracks"), {
CommandGroup(wxT("AlignMove"), alignLabels,
FN(OnAlignMoveSel), AudioIONotBusyFlag | TracksSelectedFlag),
} ),
@ -1406,7 +1408,7 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
//////////////////////////////////////////////////////////////////////////
Menu( XO("S&ort Tracks"),
Menu( wxT("Sort"), XO("S&ort Tracks"),
Command( wxT("SortByTime"), XXO("By &Start Time"), FN(OnSortTime),
TracksExistFlag,
Options{}.LongName( XO("Sort by Time") ) ),
@ -1424,17 +1426,20 @@ MenuTable::BaseItemPtr TracksMenu( AudacityProject & )
Command( wxT("SyncLock"), XXO("Sync-&Lock Tracks (on/off)"),
FN(OnSyncLock), AlwaysEnabledFlag,
Options{}.CheckState( gPrefs->Read(wxT("/GUI/SyncLockTracks"), 0L) ) )
Options{}.CheckTest( wxT("/GUI/SyncLockTracks"), false ) )
#endif
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraTrackMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraTrackMenu()
{
using namespace MenuTable;
return Menu( XO("&Track"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Track"), XO("&Track"),
Command( wxT("TrackPan"), XXO("Change P&an on Focused Track..."),
FN(OnTrackPan),
TrackPanelHasFocus | TracksExistFlag, wxT("Shift+P") ),
@ -1478,7 +1483,8 @@ MenuTable::BaseItemPtr ExtraTrackMenu( AudacityProject & )
Command( wxT("TrackMoveBottom"), XXO("Move Focused Track to &Bottom"),
FN(OnTrackMoveBottom),
AudioIONotBusyFlag | TrackPanelHasFocus | TracksExistFlag )
);
) ) };
return menu;
}
#undef FN

View File

@ -966,12 +966,12 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& TransportActions::Handler :: X)
#define FN(X) (& TransportActions::Handler :: X)
MenuTable::BaseItemPtr CursorMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr CursorMenu();
MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
// Under /MenuBar
MenuTable::BaseItemSharedPtr TransportMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
@ -981,10 +981,12 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
static const auto CanStopFlags = AudioIONotBusyFlag | CanStopAudioStreamFlag;
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
/* i18n-hint: 'Transport' is the name given to the set of controls that
play, record, pause etc. */
return Menu( XO("Tra&nsport"),
Menu( XO("Pl&aying"),
Menu( wxT("Transport"), XO("Tra&nsport"),
Menu( wxT("Play"), XO("Pl&aying"),
/* i18n-hint: (verb) Start or Stop audio playback*/
Command( wxT("PlayStop"), XXO("Pl&ay/Stop"), FN(OnPlayStop),
CanStopAudioStreamFlag, wxT("Space") ),
@ -996,14 +998,17 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
CanStopAudioStreamFlag, wxT("P") )
),
Menu( XO("&Recording"),
Menu( wxT("Record"), XO("&Recording"),
/* i18n-hint: (verb)*/
Command( wxT("Record1stChoice"), XXO("&Record"), FN(OnRecord),
CanStopFlags, wxT("R") ),
// The OnRecord2ndChoice function is: if normal record records beside,
// it records below, if normal record records below, it records beside.
// TODO: Do 'the right thing' with other options like TimerRecord.
Command( wxT("Record2ndChoice"),
// Delayed evaluation in case gPrefs is not yet defined
[](const AudacityProject&)
{ return Command( wxT("Record2ndChoice"),
// Our first choice is bound to R (by default)
// and gets the prime position.
// We supply the name for the 'other one' here.
@ -1011,8 +1016,9 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
(gPrefs->ReadBool("/GUI/PreferNewTrackRecord", false)
? XO("&Append Record") : XO("Record &New Track")),
FN(OnRecord2ndChoice), CanStopFlags,
wxT("Shift+R")
),
wxT("Shift+R"),
findCommandHandler
); },
Command( wxT("TimerRecord"), XXO("&Timer Record..."),
FN(OnTimerRecord), CanStopFlags, wxT("Shift+T") ),
@ -1032,15 +1038,15 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
),
// Scrubbing sub-menu
Scrubber::Get( project ).Menu(),
Scrubber::Menu(),
CursorMenu,
CursorMenu(),
Separator(),
//////////////////////////////////////////////////////////////////////////
Menu( XO("Pla&y Region"),
Menu( wxT("PlayRegion"), XO("Pla&y Region"),
Command( wxT("LockPlayRegion"), XXO("&Lock"), FN(OnLockPlayRegion),
PlayRegionNotLockedFlag ),
Command( wxT("UnlockPlayRegion"), XXO("&Unlock"),
@ -1052,7 +1058,7 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
Command( wxT("RescanDevices"), XXO("R&escan Audio Devices"),
FN(OnRescanDevices), AudioIONotBusyFlag | CanStopAudioStreamFlag ),
Menu( XO("Transport &Options"),
Menu( wxT("Options"), XO("Transport &Options"),
// Sound Activated recording options
Command( wxT("SoundActivationLevel"),
XXO("Sound Activation Le&vel..."), FN(OnSoundActivated),
@ -1085,13 +1091,17 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project )
AudioIONotBusyFlag | CanStopAudioStreamFlag, checkOff )
#endif
)
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraTransportMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraTransportMenu()
{
using namespace MenuTable;
return Menu( XO("T&ransport"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Transport"), XO("T&ransport"),
// PlayStop is already in the menus.
/* i18n-hint: (verb) Start playing audio*/
Command( wxT("Play"), XXO("Pl&ay"), FN(OnPlayStop),
@ -1133,13 +1143,17 @@ MenuTable::BaseItemPtr ExtraTransportMenu( AudacityProject & )
Command(wxT("KeyboardScrubForwards"), XXO("Scrub For&wards"),
FN(OnKeyboardScrubForwards),
CaptureNotBusyFlag | CanStopAudioStreamFlag, wxT("I\twantKeyup"))
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraPlayAtSpeedMenu( AudacityProject & )
// Under /MenuBar/Optional/Extra
MenuTable::BaseItemSharedPtr ExtraPlayAtSpeedMenu()
{
using namespace MenuTable;
return Menu( XO("&Play-at-Speed"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("PlayAtSpeed"), XO("&Play-at-Speed"),
/* i18n-hint: 'Normal Play-at-Speed' doesn't loop or cut preview. */
Command( wxT("PlayAtSpeed"), XXO("Normal Pl&ay-at-Speed"),
FN(OnPlayAtSpeed), CaptureNotBusyFlag ),
@ -1163,7 +1177,8 @@ MenuTable::BaseItemPtr ExtraPlayAtSpeedMenu( AudacityProject & )
Command( wxT("MoveToNextLabel"), XXO("Move to &Next Label"),
FN(OnMoveToNextLabel),
CaptureNotBusyFlag | TrackPanelHasFocus, wxT("Alt+Right") )
);
) ) };
return menu;
}
#undef FN

View File

@ -430,20 +430,22 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &project) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& ViewActions::Handler :: X)
#define FN(X) (& ViewActions::Handler :: X)
MenuTable::BaseItemPtr ToolbarsMenu( AudacityProject& );
MenuTable::BaseItemSharedPtr ToolbarsMenu();
MenuTable::BaseItemPtr ViewMenu( AudacityProject& )
// Under /MenuBar
MenuTable::BaseItemSharedPtr ViewMenu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
static const auto checkOff = Options{}.CheckState( false );
return Menu( XO("&View"),
Menu( XO("&Zoom"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("View"), XO("&View"),
Menu( wxT("Zoom"), XO("&Zoom"),
Command( wxT("ZoomIn"), XXO("Zoom &In"), FN(OnZoomIn),
ZoomInAvailableFlag, wxT("Ctrl+1") ),
Command( wxT("ZoomNormal"), XXO("Zoom &Normal"), FN(OnZoomNormal),
@ -457,10 +459,10 @@ MenuTable::BaseItemPtr ViewMenu( AudacityProject& )
Separator(),
Command( wxT("AdvancedVZoom"), XXO("Advanced &Vertical Zooming"),
FN(OnAdvancedVZoom), AlwaysEnabledFlag,
Options{}.CheckState( gPrefs->Read(wxT("/GUI/VerticalZooming"), 0L) ) )
Options{}.CheckTest( wxT("/GUI/VerticalZooming"), false ) )
),
Menu( XO("T&rack Size"),
Menu( wxT("TrackSize"), XO("T&rack Size"),
Command( wxT("FitInWindow"), XXO("&Fit to Width"), FN(OnZoomFit),
TracksExistFlag, wxT("Ctrl+F") ),
Command( wxT("FitV"), XXO("Fit to &Height"), FN(OnZoomFitV),
@ -471,7 +473,7 @@ MenuTable::BaseItemPtr ViewMenu( AudacityProject& )
FN(OnExpandAllTracks), TracksExistFlag, wxT("Ctrl+Shift+X") )
),
Menu( XO("Sk&ip to"),
Menu( wxT("SkipTo"), XO("Sk&ip to"),
Command( wxT("SkipSelStart"), XXO("Selection Sta&rt"),
FN(OnGoSelStart), TimeSelectedFlag,
Options{ wxT("Ctrl+["), XO("Skip to Selection Start") } ),
@ -532,22 +534,24 @@ MenuTable::BaseItemPtr ViewMenu( AudacityProject& )
//////////////////////////////////////////////////////////////////////////
ToolbarsMenu,
ToolbarsMenu(),
Separator(),
Command( wxT("ShowExtraMenus"), XXO("&Extra Menus (on/off)"),
FN(OnShowExtraMenus), AlwaysEnabledFlag,
Options{}.CheckState( gPrefs->Read(wxT("/GUI/ShowExtraMenus"), 0L) ) ),
Options{}.CheckTest( wxT("/GUI/ShowExtraMenus"), false ) ),
Command( wxT("ShowClipping"), XXO("&Show Clipping (on/off)"),
FN(OnShowClipping), AlwaysEnabledFlag,
Options{}.CheckState( gPrefs->Read(wxT("/GUI/ShowClipping"), 0L) ) )
Options{}.CheckTest( wxT("/GUI/ShowClipping"), false ) )
#if defined(EXPERIMENTAL_EFFECTS_RACK)
,
Command( wxT("ShowEffectsRack"), XXO("Show Effects Rack"),
FN(OnShowEffectsRack), AlwaysEnabledFlag, checkOff )
#endif
);
) ) };
return menu;
}
#undef FN

View File

@ -116,16 +116,18 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
// Menu definitions
#define FN(X) findCommandHandler, \
static_cast<CommandFunctorPointer>(& WindowActions::Handler :: X)
#define FN(X) (& WindowActions::Handler :: X)
MenuTable::BaseItemPtr WindowMenu( AudacityProject & )
// Under /MenuBar
MenuTable::BaseItemSharedPtr WindowMenu()
{
//////////////////////////////////////////////////////////////////////////
// poor imitation of the Mac Windows Menu
//////////////////////////////////////////////////////////////////////////
using namespace MenuTable;
return Menu( XO("&Window"),
static BaseItemSharedPtr menu{
FinderScope( findCommandHandler ).Eval(
Menu( wxT("Window"), XO("&Window"),
/* i18n-hint: Standard Macintosh Window menu item: Make (the current
* window) shrink to an icon on the dock */
Command( wxT("MacMinimize"), XXO("&Minimize"), FN(OnMacMinimize),
@ -141,20 +143,24 @@ MenuTable::BaseItemPtr WindowMenu( AudacityProject & )
* windows un-hidden */
Command( wxT("MacBringAllToFront"), XXO("&Bring All to Front"),
FN(OnMacBringAllToFront), AlwaysEnabledFlag )
);
) ) };
return menu;
}
MenuTable::BaseItemPtr ExtraWindowItems( AudacityProject & )
// Under /MenuBar/Optional/Extra/Misc
MenuTable::BaseItemSharedPtr ExtraWindowItems()
{
using namespace MenuTable;
return Items(
static BaseItemSharedPtr items{
FinderScope( findCommandHandler ).Eval(
Items( wxT("MacWindows"),
/* i18n-hint: Shrink all project windows to icons on the Macintosh
tooldock */
Command( wxT("MacMinimizeAll"), XXO("Minimize All Projects"),
FN(OnMacMinimizeAll),
AlwaysEnabledFlag, wxT("Ctrl+Alt+M") )
);
) ) };
return items;
}
#undef FN
@ -162,12 +168,12 @@ MenuTable::BaseItemPtr ExtraWindowItems( AudacityProject & )
#else
// Not WXMAC. Stub functions.
MenuTable::BaseItemPtr WindowMenu( AudacityProject & )
MenuTable::BaseItemSharedPtr WindowMenu()
{
return nullptr;
}
MenuTable::BaseItemPtr ExtraWindowItems( AudacityProject & )
MenuTable::BaseItemSharedPtr ExtraWindowItems()
{
return nullptr;
}

View File

@ -360,6 +360,10 @@ wxString GUIPrefs::SetLang( const wxString & lang )
// we're not using them yet...
using future1 = decltype( XO("Master Gain Control") );
#ifdef __WXMAC__
wxApp::s_macHelpMenuTitleName = _("&Help");
#endif
return result;
}

View File

@ -258,7 +258,7 @@ static const ReservedCommandFlag
HasWaveDataFlag{ HasWaveDataPred }; // jkc
namespace {
const struct MenuItem {
struct MenuItem {
CommandID name;
TranslatableString label;
TranslatableString status;
@ -268,7 +268,11 @@ namespace {
bool (Scrubber::*StatusTest)() const;
const TranslatableString &GetStatus() const { return status; }
} menuItems[] = {
};
using MenuItems = std::vector< MenuItem >;
const MenuItems &menuItems()
{
static MenuItems theItems{
/* i18n-hint: These commands assist the user in finding a sound by ear. ...
"Scrubbing" is variable-speed playback, ...
"Seeking" is normal speed playback but with skips, ...
@ -287,13 +291,13 @@ namespace {
AlwaysEnabledFlag,
&Scrubber::OnToggleScrubRuler, false, &Scrubber::ShowsBar,
},
};
return theItems;
};
enum { nMenuItems = sizeof(menuItems) / sizeof(*menuItems) };
inline const MenuItem &FindMenuItem(bool seek)
{
return *std::find_if(menuItems, menuItems + nMenuItems,
return *std::find_if(menuItems().begin(), menuItems().end(),
[=](const MenuItem &item) {
return seek == item.seek;
}
@ -1055,7 +1059,7 @@ BEGIN_EVENT_TABLE(Scrubber, wxEvtHandler)
EVT_MENU(CMD_ID + 2, THUNK(OnToggleScrubRuler))
END_EVENT_TABLE()
static_assert(nMenuItems == 3, "wrong number of items");
//static_assert(menuItems().size() == 3, "wrong number of items");
static auto sPlayAtSpeedStatus = XO("Playing at Speed");
@ -1101,7 +1105,7 @@ registeredStatusWidthFunction{
if ( field == stateStatusBarField ) {
TranslatableStrings strings;
// Note that Scrubbing + Paused is not allowed.
for (const auto &item : menuItems)
for (const auto &item : menuItems())
strings.push_back( item.GetStatus() );
strings.push_back(
XO("%s Paused.").Format( sPlayAtSpeedStatus )
@ -1121,35 +1125,44 @@ bool Scrubber::CanScrub() const
HasWaveDataPred( *mProject );
}
// To supply the "finder" argument
static CommandHandlerObject &findme(AudacityProject &project)
{ return Scrubber::Get( project ); }
MenuTable::BaseItemPtr Scrubber::Menu()
MenuTable::BaseItemSharedPtr Scrubber::Menu()
{
using namespace MenuTable;
using Options = CommandManager::Options;
MenuTable::BaseItemPtrs ptrs;
for (const auto &item : menuItems) {
ptrs.push_back( MenuTable::Command( item.name, item.label,
findme, static_cast<CommandFunctorPointer>(item.memFn),
item.flags,
item.StatusTest
? // a checkmark item
Options{}.CheckState( (this->*item.StatusTest)() )
: // not a checkmark item
Options{}
) );
}
return MenuTable::Menu( XO("Scru&bbing"), std::move( ptrs ) );
static BaseItemSharedPtr menu {
FinderScope(
[](AudacityProject &project) -> CommandHandlerObject&
{ return Scrubber::Get( project ); }
).Eval(
MenuTable::Menu( wxT("Scrubbing"),
XO("Scru&bbing"),
[]{
BaseItemPtrs ptrs;
for (const auto &item : menuItems()) {
ptrs.push_back( MenuTable::Command( item.name, item.label,
item.memFn,
item.flags,
item.StatusTest
? // a checkmark item
Options{}.CheckTest( [&item](AudacityProject &project){
return ( Scrubber::Get(project).*(item.StatusTest) )(); } )
: // not a checkmark item
Options{}
) );
}
return ptrs;
}()
) ) };
return menu;
}
void Scrubber::PopulatePopupMenu(wxMenu &menu)
{
int id = CMD_ID;
auto &cm = CommandManager::Get( *mProject );
for (const auto &item : menuItems) {
for (const auto &item : menuItems()) {
if (cm.GetEnabled(item.name)) {
auto test = item.StatusTest;
menu.Append(id, item.label.Translation(), wxString{},
@ -1164,7 +1177,7 @@ void Scrubber::PopulatePopupMenu(wxMenu &menu)
void Scrubber::CheckMenuItems()
{
auto &cm = CommandManager::Get( *mProject );
for (const auto &item : menuItems) {
for (const auto &item : menuItems()) {
auto test = item.StatusTest;
if (test)
cm.Check(item.name, (this->*test)());

View File

@ -118,7 +118,7 @@ public:
bool CanScrub() const;
// For the toolbar
MenuTable::BaseItemPtr Menu();
static MenuTable::BaseItemSharedPtr Menu();
// For popup
void PopulatePopupMenu(wxMenu &menu);