702 lines
24 KiB
C++
702 lines
24 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
CommandManager.h
|
|
|
|
Brian Gunlogson
|
|
Dominic Mazzoni
|
|
|
|
**********************************************************************/
|
|
|
|
#ifndef __AUDACITY_COMMAND_MANAGER__
|
|
#define __AUDACITY_COMMAND_MANAGER__
|
|
|
|
#include "audacity/Types.h"
|
|
|
|
#include "../ClientData.h"
|
|
#include "CommandFunctors.h"
|
|
#include "CommandFlag.h"
|
|
|
|
#include "Keyboard.h"
|
|
|
|
#include "../Prefs.h"
|
|
#include "../Registry.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "../xml/XMLTagHandler.h"
|
|
|
|
#include "audacity/Types.h"
|
|
|
|
#include <unordered_map>
|
|
|
|
class wxMenu;
|
|
class wxMenuBar;
|
|
using CommandParameter = CommandID;
|
|
|
|
struct MenuBarListEntry;
|
|
struct SubMenuListEntry;
|
|
struct CommandListEntry;
|
|
|
|
using MenuBarList = std::vector < MenuBarListEntry >;
|
|
using SubMenuList = std::vector < SubMenuListEntry >;
|
|
|
|
// This is an array of pointers, not structures, because the hash maps also point to them,
|
|
// so we don't want the structures to relocate with vector operations.
|
|
using CommandList = std::vector<std::unique_ptr<CommandListEntry>>;
|
|
|
|
using CommandKeyHash = std::unordered_map<NormalizedKeyString, CommandListEntry*>;
|
|
using CommandNameHash = std::unordered_map<CommandID, CommandListEntry*>;
|
|
using CommandNumericIDHash = std::unordered_map<int, CommandListEntry*>;
|
|
|
|
class AudacityProject;
|
|
class CommandContext;
|
|
|
|
class AUDACITY_DLL_API CommandManager final
|
|
: public XMLTagHandler
|
|
, public ClientData::Base
|
|
{
|
|
public:
|
|
static CommandManager &Get( AudacityProject &project );
|
|
static const CommandManager &Get( const AudacityProject &project );
|
|
|
|
// Type of a function that can intercept menu item handling.
|
|
// If it returns true, bypass the usual dipatch of commands.
|
|
using MenuHook = std::function< bool(const CommandID&) >;
|
|
|
|
// install a menu hook, returning the previously installed one
|
|
static MenuHook SetMenuHook( const MenuHook &hook );
|
|
|
|
//
|
|
// Constructor / Destructor
|
|
//
|
|
|
|
CommandManager();
|
|
virtual ~CommandManager();
|
|
|
|
CommandManager(const CommandManager&) PROHIBITED;
|
|
CommandManager &operator= (const CommandManager&) PROHIBITED;
|
|
|
|
void SetMaxList();
|
|
void PurgeData();
|
|
|
|
//
|
|
// Creating menus and adding commands
|
|
//
|
|
|
|
std::unique_ptr<wxMenuBar> AddMenuBar(const wxString & sMenu);
|
|
|
|
wxMenu *BeginMenu(const TranslatableString & tName);
|
|
void EndMenu();
|
|
|
|
// type of a function that determines checkmark state
|
|
using CheckFn = std::function< bool(AudacityProject&) >;
|
|
|
|
// For specifying unusual arguments in AddItem
|
|
struct AUDACITY_DLL_API Options
|
|
{
|
|
Options() {}
|
|
// Allow implicit construction from an accelerator string, which is
|
|
// a very common case
|
|
Options( const wxChar *accel_ ) : accel{ accel_ } {}
|
|
// A two-argument constructor for another common case
|
|
Options(
|
|
const wxChar *accel_,
|
|
const TranslatableString &longName_ )
|
|
: accel{ accel_ }, longName{ longName_ } {}
|
|
|
|
Options &&Accel (const wxChar *value) &&
|
|
{ accel = value; return std::move(*this); }
|
|
Options &&IsEffect (bool value = true) &&
|
|
{ bIsEffect = value; return std::move(*this); }
|
|
Options &&Parameter (const CommandParameter &value) &&
|
|
{ parameter = value; return std::move(*this); }
|
|
Options &&LongName (const TranslatableString &value ) &&
|
|
{ longName = value; return std::move(*this); }
|
|
Options &&IsGlobal () &&
|
|
{ global = true; return std::move(*this); }
|
|
Options &&UseStrictFlags () &&
|
|
{ useStrictFlags = true; return std::move(*this); }
|
|
Options &&WantKeyUp () &&
|
|
{ wantKeyUp = true; return std::move(*this); }
|
|
Options &&SkipKeyDown () &&
|
|
{ skipKeyDown = true; return std::move(*this); }
|
|
|
|
// This option affects debugging only:
|
|
Options &&AllowDup () &&
|
|
{ allowDup = true; return std::move(*this); }
|
|
|
|
Options &&AllowInMacros ( int value = 1 ) &&
|
|
{ allowInMacros = value; 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("") };
|
|
CheckFn checker; // default value means it's not a check item
|
|
bool bIsEffect{ false };
|
|
CommandParameter parameter{};
|
|
TranslatableString longName{};
|
|
bool global{ false };
|
|
bool useStrictFlags{ false };
|
|
bool wantKeyUp{ false };
|
|
bool skipKeyDown{ false };
|
|
bool allowDup{ 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,
|
|
const ComponentInterfaceSymbol items[],
|
|
size_t nItems,
|
|
CommandHandlerFinder finder,
|
|
CommandFunctorPointer callback,
|
|
CommandFlag flags,
|
|
bool bIsEffect = false);
|
|
|
|
void AddItem(AudacityProject &project,
|
|
const CommandID & name,
|
|
const TranslatableString &label_in,
|
|
CommandHandlerFinder finder,
|
|
CommandFunctorPointer callback,
|
|
CommandFlag flags,
|
|
const Options &options = {});
|
|
|
|
void AddSeparator();
|
|
|
|
void PopMenuBar();
|
|
void BeginOccultCommands();
|
|
void EndOccultCommands();
|
|
|
|
|
|
void SetCommandFlags(const CommandID &name, CommandFlag flags);
|
|
|
|
//
|
|
// Modifying menus
|
|
//
|
|
|
|
void EnableUsingFlags(
|
|
CommandFlag flags, CommandFlag strictFlags);
|
|
void Enable(const wxString &name, bool enabled);
|
|
void Check(const CommandID &name, bool checked);
|
|
void Modify(const wxString &name, const TranslatableString &newLabel);
|
|
|
|
//
|
|
// Modifying accelerators
|
|
//
|
|
|
|
void SetKeyFromName(const CommandID &name, const NormalizedKeyString &key);
|
|
void SetKeyFromIndex(int i, const NormalizedKeyString &key);
|
|
|
|
//
|
|
// Executing commands
|
|
//
|
|
|
|
// "permit" allows filtering even if the active window isn't a child of the project.
|
|
// Lyrics and MixerTrackCluster classes use it.
|
|
bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit = false);
|
|
bool HandleMenuID(AudacityProject &project, int id, CommandFlag flags, bool alwaysEnabled);
|
|
void RegisterLastAnalyzer(const CommandContext& context);
|
|
void RegisterLastTool(const CommandContext& context);
|
|
void DoRepeatProcess(const CommandContext& context, int);
|
|
|
|
enum TextualCommandResult {
|
|
CommandFailure,
|
|
CommandSuccess,
|
|
CommandNotFound
|
|
};
|
|
|
|
TextualCommandResult
|
|
HandleTextualCommand(const CommandID & Str,
|
|
const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
|
|
|
|
//
|
|
// Accessing
|
|
//
|
|
|
|
TranslatableStrings GetCategories( AudacityProject& );
|
|
void GetAllCommandNames(CommandIDs &names, bool includeMultis) const;
|
|
void GetAllCommandLabels(
|
|
TranslatableStrings &labels, std::vector<bool> &vExcludeFromMacros,
|
|
bool includeMultis) const;
|
|
void GetAllCommandData(
|
|
CommandIDs &names,
|
|
std::vector<NormalizedKeyString> &keys,
|
|
std::vector<NormalizedKeyString> &default_keys,
|
|
TranslatableStrings &labels, TranslatableStrings &categories,
|
|
#if defined(EXPERIMENTAL_KEY_VIEW)
|
|
TranslatableStrings &prefixes,
|
|
#endif
|
|
bool includeMultis);
|
|
|
|
// Each command is assigned a numerical ID for use in wxMenu and wxEvent,
|
|
// which need not be the same across platforms or sessions
|
|
CommandID GetNameFromNumericID( int id );
|
|
|
|
TranslatableString GetLabelFromName(const CommandID &name);
|
|
TranslatableString GetPrefixedLabelFromName(const CommandID &name);
|
|
TranslatableString GetCategoryFromName(const CommandID &name);
|
|
NormalizedKeyString GetKeyFromName(const CommandID &name) const;
|
|
NormalizedKeyString GetDefaultKeyFromName(const CommandID &name);
|
|
|
|
bool GetEnabled(const CommandID &name);
|
|
int GetNumberOfKeysRead() const;
|
|
|
|
#if defined(_DEBUG)
|
|
void CheckDups();
|
|
#endif
|
|
void RemoveDuplicateShortcuts();
|
|
|
|
//
|
|
// Loading/Saving
|
|
//
|
|
|
|
void WriteXML(XMLWriter &xmlFile) const /* not override */;
|
|
|
|
///
|
|
/// Formatting summaries that include shortcut keys
|
|
///
|
|
TranslatableString DescribeCommandsAndShortcuts
|
|
(
|
|
// If a shortcut key is defined for the command, then it is appended,
|
|
// parenthesized, after the translated name.
|
|
const ComponentInterfaceSymbol commands[], size_t nCommands) const;
|
|
|
|
// Sorted list of the shortcut keys to be excluded from the standard defaults
|
|
static const std::vector<NormalizedKeyString> &ExcludedList();
|
|
|
|
private:
|
|
|
|
//
|
|
// Creating menus and adding commands
|
|
//
|
|
|
|
int NextIdentifier(int ID);
|
|
CommandListEntry *NewIdentifier(const CommandID & name,
|
|
const TranslatableString & label,
|
|
wxMenu *menu,
|
|
CommandHandlerFinder finder,
|
|
CommandFunctorPointer callback,
|
|
const CommandID &nameSuffix,
|
|
int index,
|
|
int count,
|
|
const Options &options);
|
|
|
|
void AddGlobalCommand(const CommandID &name,
|
|
const TranslatableString &label,
|
|
CommandHandlerFinder finder,
|
|
CommandFunctorPointer callback,
|
|
const Options &options = {});
|
|
|
|
//
|
|
// Executing commands
|
|
//
|
|
|
|
bool HandleCommandEntry(AudacityProject &project,
|
|
const CommandListEntry * entry, CommandFlag flags,
|
|
bool alwaysEnabled, const wxEvent * evt = NULL);
|
|
|
|
//
|
|
// Modifying
|
|
//
|
|
|
|
void Enable(CommandListEntry *entry, bool enabled);
|
|
wxMenu *BeginMainMenu(const TranslatableString & tName);
|
|
void EndMainMenu();
|
|
wxMenu* BeginSubMenu(const TranslatableString & tName);
|
|
void EndSubMenu();
|
|
|
|
//
|
|
// Accessing
|
|
//
|
|
|
|
wxMenuBar * CurrentMenuBar() const;
|
|
wxMenuBar * GetMenuBar(const wxString & sMenu) const;
|
|
wxMenu * CurrentSubMenu() const;
|
|
public:
|
|
wxMenu * CurrentMenu() const;
|
|
|
|
void UpdateCheckmarks( AudacityProject &project );
|
|
private:
|
|
wxString FormatLabelForMenu(const CommandListEntry *entry) const;
|
|
wxString FormatLabelWithDisabledAccel(const CommandListEntry *entry) const;
|
|
|
|
//
|
|
// Loading/Saving
|
|
//
|
|
|
|
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
|
|
void HandleXMLEndTag(const wxChar *tag) override;
|
|
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
|
|
|
|
private:
|
|
// mMaxList only holds shortcuts that should not be added (by default)
|
|
// and is sorted.
|
|
std::vector<NormalizedKeyString> mMaxListOnly;
|
|
|
|
MenuBarList mMenuBarList;
|
|
SubMenuList mSubMenuList;
|
|
CommandList mCommandList;
|
|
CommandNameHash mCommandNameHash;
|
|
CommandKeyHash mCommandKeyHash;
|
|
CommandNumericIDHash mCommandNumericIDHash;
|
|
int mCurrentID;
|
|
int mXMLKeysRead;
|
|
|
|
bool mbSeparatorAllowed; // false at the start of a menu and immediately after a separator.
|
|
|
|
TranslatableString mCurrentMenuName;
|
|
TranslatableString mNiceName;
|
|
int mLastProcessId;
|
|
std::unique_ptr<wxMenu> uCurrentMenu;
|
|
wxMenu *mCurrentMenu {};
|
|
|
|
bool bMakingOccultCommands;
|
|
std::unique_ptr< wxMenuBar > mTempMenuBar;
|
|
};
|
|
|
|
struct AUDACITY_DLL_API MenuVisitor : Registry::Visitor
|
|
{
|
|
// final overrides
|
|
void BeginGroup( Registry::GroupItem &item, const Path &path ) final;
|
|
void EndGroup( Registry::GroupItem &item, const Path& ) final;
|
|
void Visit( Registry::SingleItem &item, const Path &path ) final;
|
|
|
|
// added virtuals
|
|
virtual void DoBeginGroup( Registry::GroupItem &item, const Path &path );
|
|
virtual void DoEndGroup( Registry::GroupItem &item, const Path &path );
|
|
virtual void DoVisit( Registry::SingleItem &item, const Path &path );
|
|
virtual void DoSeparator();
|
|
|
|
private:
|
|
void MaybeDoSeparator();
|
|
std::vector<bool> firstItem;
|
|
std::vector<bool> needSeparator;
|
|
};
|
|
|
|
struct ToolbarMenuVisitor : MenuVisitor
|
|
{
|
|
explicit ToolbarMenuVisitor( AudacityProject &p ) : project{ p } {}
|
|
operator AudacityProject & () const { return project; }
|
|
AudacityProject &project;
|
|
};
|
|
|
|
// Define items that populate tables that specifically describe menu trees
|
|
namespace MenuTable {
|
|
using namespace Registry;
|
|
|
|
// These are found by dynamic_cast
|
|
struct AUDACITY_DLL_API MenuSection {
|
|
virtual ~MenuSection();
|
|
};
|
|
struct AUDACITY_DLL_API WholeMenu {
|
|
WholeMenu( bool extend = false ) : extension{ extend } {}
|
|
virtual ~WholeMenu();
|
|
bool extension;
|
|
};
|
|
|
|
// Describes a main menu in the toolbar, or a sub-menu
|
|
struct AUDACITY_DLL_API MenuItem final
|
|
: ConcreteGroupItem< false, ToolbarMenuVisitor >
|
|
, WholeMenu {
|
|
// Construction from an internal name and a previously built-up
|
|
// vector of pointers
|
|
MenuItem( const Identifier &internalName,
|
|
const TranslatableString &title_, BaseItemPtrs &&items_ );
|
|
// In-line, variadic constructor that doesn't require building a vector
|
|
template< typename... Args >
|
|
MenuItem( const Identifier &internalName,
|
|
const TranslatableString &title_, Args&&... args )
|
|
: ConcreteGroupItem< false, ToolbarMenuVisitor >{
|
|
internalName, std::forward<Args>(args)... }
|
|
, title{ title_ }
|
|
{}
|
|
~MenuItem() override;
|
|
|
|
TranslatableString title;
|
|
};
|
|
|
|
// Collects other items that are conditionally shown or hidden, but are
|
|
// always available to macro programming
|
|
struct ConditionalGroupItem final
|
|
: ConcreteGroupItem< false, ToolbarMenuVisitor > {
|
|
using Condition = std::function< bool() >;
|
|
|
|
// Construction from an internal name and a previously built-up
|
|
// vector of pointers
|
|
ConditionalGroupItem( const Identifier &internalName,
|
|
Condition condition_, BaseItemPtrs &&items_ );
|
|
// In-line, variadic constructor that doesn't require building a vector
|
|
template< typename... Args >
|
|
ConditionalGroupItem( const Identifier &internalName,
|
|
Condition condition_, Args&&... args )
|
|
: ConcreteGroupItem< false, ToolbarMenuVisitor >{
|
|
internalName, std::forward<Args>(args)... }
|
|
, condition{ condition_ }
|
|
{}
|
|
~ConditionalGroupItem() override;
|
|
|
|
Condition condition;
|
|
};
|
|
|
|
// usage:
|
|
// auto scope = FinderScope( findCommandHandler );
|
|
// return Items( ... );
|
|
//
|
|
// or:
|
|
// return ( FinderScope( findCommandHandler ), 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 AUDACITY_DLL_API FinderScope : ValueRestorer< CommandHandlerFinder >
|
|
{
|
|
static CommandHandlerFinder sFinder;
|
|
|
|
public:
|
|
static CommandHandlerFinder DefaultFinder() { return sFinder; }
|
|
|
|
explicit
|
|
FinderScope( CommandHandlerFinder finder )
|
|
: ValueRestorer( sFinder, finder )
|
|
{}
|
|
};
|
|
|
|
// Describes one command in a menu
|
|
struct AUDACITY_DLL_API CommandItem final : SingleItem {
|
|
CommandItem(const CommandID &name_,
|
|
const TranslatableString &label_in_,
|
|
CommandFunctorPointer callback_,
|
|
CommandFlag flags_,
|
|
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 TranslatableString label_in;
|
|
CommandHandlerFinder finder;
|
|
CommandFunctorPointer callback;
|
|
CommandFlag flags;
|
|
CommandManager::Options options;
|
|
};
|
|
|
|
// 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 AUDACITY_DLL_API CommandGroupItem final : SingleItem {
|
|
CommandGroupItem(const Identifier &name_,
|
|
std::vector< ComponentInterfaceSymbol > items_,
|
|
CommandFunctorPointer callback_,
|
|
CommandFlag flags_,
|
|
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 Identifier &name_,
|
|
std::vector< ComponentInterfaceSymbol > items_,
|
|
void (Handler::*pmf)(const CommandContext&),
|
|
CommandFlag flags_,
|
|
bool isEffect_,
|
|
CommandHandlerFinder finder = FinderScope::DefaultFinder())
|
|
: CommandGroupItem(name_, std::move(items_),
|
|
static_cast<CommandFunctorPointer>(pmf),
|
|
flags_, isEffect_, finder)
|
|
{}
|
|
|
|
~CommandGroupItem() override;
|
|
|
|
const std::vector<ComponentInterfaceSymbol> items;
|
|
CommandHandlerFinder finder;
|
|
CommandFunctorPointer callback;
|
|
CommandFlag flags;
|
|
bool isEffect;
|
|
};
|
|
|
|
// For manipulating the enclosing menu or sub-menu directly,
|
|
// adding any number of items, not using the CommandManager
|
|
struct SpecialItem final : SingleItem
|
|
{
|
|
using Appender = std::function< void( AudacityProject&, wxMenu& ) >;
|
|
|
|
explicit SpecialItem( const Identifier &internalName, const Appender &fn_ )
|
|
: SingleItem{ internalName }
|
|
, fn{ fn_ }
|
|
{}
|
|
~SpecialItem() override;
|
|
|
|
Appender fn;
|
|
};
|
|
|
|
struct MenuPart : ConcreteGroupItem< false, ToolbarMenuVisitor >, MenuSection
|
|
{
|
|
template< typename... Args >
|
|
explicit
|
|
MenuPart( const Identifier &internalName, Args&&... args )
|
|
: ConcreteGroupItem< false, ToolbarMenuVisitor >{
|
|
internalName, std::forward< Args >( args )... }
|
|
{}
|
|
};
|
|
using MenuItems = ConcreteGroupItem< true, ToolbarMenuVisitor >;
|
|
|
|
// The following, and Shared(), are the functions to use directly
|
|
// in writing table definitions.
|
|
|
|
// 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.
|
|
// 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 std::unique_ptr< MenuItems > Items(
|
|
const Identifier &internalName, Args&&... args )
|
|
{ return std::make_unique< MenuItems >(
|
|
internalName, std::forward<Args>(args)... ); }
|
|
|
|
// Like Items, but insert a menu separator between the menu section and
|
|
// any other items or sections before or after it in the same (innermost,
|
|
// enclosing) menu.
|
|
// It's not necessary that the sisters of sections be other sections, but it
|
|
// might clarify the logical groupings.
|
|
template< typename... Args >
|
|
inline std::unique_ptr< MenuPart > Section(
|
|
const Identifier &internalName, Args&&... args )
|
|
{ return std::make_unique< MenuPart >(
|
|
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.
|
|
// 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 std::unique_ptr<MenuItem> Menu(
|
|
const Identifier &internalName, const TranslatableString &title, Args&&... args )
|
|
{ return std::make_unique<MenuItem>(
|
|
internalName, title, std::forward<Args>(args)... ); }
|
|
inline std::unique_ptr<MenuItem> Menu(
|
|
const Identifier &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 std::unique_ptr<ConditionalGroupItem> ConditionalItems(
|
|
const Identifier &internalName,
|
|
ConditionalGroupItem::Condition condition, Args&&... args )
|
|
{ return std::make_unique<ConditionalGroupItem>(
|
|
internalName, condition, std::forward<Args>(args)... ); }
|
|
inline std::unique_ptr<ConditionalGroupItem> ConditionalItems(
|
|
const Identifier &internalName, ConditionalGroupItem::Condition condition,
|
|
BaseItemPtrs &&items )
|
|
{ return std::make_unique<ConditionalGroupItem>(
|
|
internalName, condition, std::move( items ) ); }
|
|
|
|
// Make either a menu item or just a group, depending on the nonemptiness
|
|
// 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 Identifier &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 Identifier &internalName,
|
|
const TranslatableString &title, BaseItemPtrs &&items )
|
|
{ if ( title.empty() )
|
|
return Items( internalName, std::move( items ) );
|
|
else
|
|
return std::make_unique<MenuItem>(
|
|
internalName, title, std::move( items ) ); }
|
|
|
|
template< typename Handler >
|
|
inline std::unique_ptr<CommandItem> Command(
|
|
const CommandID &name,
|
|
const TranslatableString &label_in,
|
|
void (Handler::*pmf)(const CommandContext&),
|
|
CommandFlag flags, const CommandManager::Options &options = {},
|
|
CommandHandlerFinder finder = FinderScope::DefaultFinder())
|
|
{
|
|
return std::make_unique<CommandItem>(
|
|
name, label_in, pmf, flags, options, finder
|
|
);
|
|
}
|
|
|
|
template< typename Handler >
|
|
inline std::unique_ptr<CommandGroupItem> CommandGroup(
|
|
const Identifier &name,
|
|
std::vector< ComponentInterfaceSymbol > items,
|
|
void (Handler::*pmf)(const CommandContext&),
|
|
CommandFlag flags, bool isEffect = false,
|
|
CommandHandlerFinder finder = FinderScope::DefaultFinder())
|
|
{
|
|
return std::make_unique<CommandGroupItem>(
|
|
name, std::move(items), pmf, flags, isEffect, finder
|
|
);
|
|
}
|
|
|
|
inline std::unique_ptr<SpecialItem> Special(
|
|
const Identifier &name, const SpecialItem::Appender &fn )
|
|
{ return std::make_unique<SpecialItem>( name, fn ); }
|
|
|
|
// Typically you make a static object of this type in the .cpp file that
|
|
// also defines the added menu actions.
|
|
// pItem can be specified by an expression using the inline functions above.
|
|
struct AUDACITY_DLL_API AttachedItem final
|
|
{
|
|
AttachedItem( const Placement &placement, BaseItemPtr pItem );
|
|
|
|
AttachedItem( const wxString &path, BaseItemPtr pItem )
|
|
// Delegating constructor
|
|
: AttachedItem( Placement{ path }, std::move( pItem ) )
|
|
{}
|
|
};
|
|
|
|
void DestroyRegistry();
|
|
|
|
}
|
|
|
|
#endif
|