2015-07-11 18:37:53 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
|
|
|
|
PopupMenuTable.h
|
|
|
|
|
|
|
|
Paul Licameli
|
|
|
|
|
|
|
|
This file defines PopupMenuTable, which inherits from wxEventHandler,
|
|
|
|
|
|
|
|
associated macros simplifying the population of tables,
|
|
|
|
|
|
|
|
and PopupMenuTable::Menu which is buildable from one or more such
|
|
|
|
tables, and automatically attaches and detaches the event handlers.
|
|
|
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#ifndef __AUDACITY_POPUP_MENU_TABLE__
|
|
|
|
#define __AUDACITY_POPUP_MENU_TABLE__
|
|
|
|
|
|
|
|
class wxCommandEvent;
|
|
|
|
class wxString;
|
|
|
|
#include <vector>
|
2018-11-14 21:30:11 +00:00
|
|
|
#include <wx/menu.h> // to inherit wxMenu
|
2015-07-11 18:37:53 +00:00
|
|
|
#include "../MemoryX.h"
|
|
|
|
|
2019-12-16 20:10:35 +00:00
|
|
|
#include "../Internat.h"
|
2020-02-05 23:01:28 +00:00
|
|
|
#include "../commands/CommandManager.h"
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
class PopupMenuTable;
|
|
|
|
|
2020-02-05 23:01:28 +00:00
|
|
|
struct PopupMenuTableEntry : Registry::SingleItem
|
2015-07-11 18:37:53 +00:00
|
|
|
{
|
2020-02-05 23:01:28 +00:00
|
|
|
enum Type { Item, RadioItem, CheckItem };
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
Type type;
|
|
|
|
int id;
|
2019-12-16 20:10:35 +00:00
|
|
|
TranslatableString caption;
|
2018-02-12 21:45:54 +00:00
|
|
|
wxCommandEventFunction func;
|
2015-07-11 18:37:53 +00:00
|
|
|
PopupMenuTable *subTable;
|
|
|
|
|
2020-02-05 23:01:28 +00:00
|
|
|
PopupMenuTableEntry( const Identifier &stringId,
|
|
|
|
Type type_, int id_, const TranslatableString &caption_,
|
|
|
|
wxCommandEventFunction func_)
|
|
|
|
: SingleItem{ stringId }
|
|
|
|
, type(type_)
|
2015-07-11 18:37:53 +00:00
|
|
|
, id(id_)
|
|
|
|
, caption(caption_)
|
|
|
|
, func(func_)
|
|
|
|
{}
|
|
|
|
|
2020-02-05 23:01:28 +00:00
|
|
|
~PopupMenuTableEntry() override;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PopupSubMenu : Registry::ConcreteGroupItem< false >
|
2020-02-06 21:51:54 +00:00
|
|
|
, MenuTable::WholeMenu
|
2020-02-05 23:01:28 +00:00
|
|
|
{
|
|
|
|
TranslatableString caption;
|
2020-02-08 18:01:23 +00:00
|
|
|
PopupMenuTable &table;
|
2020-02-05 23:01:28 +00:00
|
|
|
|
|
|
|
PopupSubMenu( const Identifier &stringId,
|
|
|
|
const TranslatableString &caption_, PopupMenuTable &table );
|
|
|
|
|
|
|
|
~PopupSubMenu() override;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PopupMenuSection
|
|
|
|
: Registry::ConcreteGroupItem< false >
|
|
|
|
, MenuTable::MenuSection {
|
|
|
|
using ConcreteGroupItem< false >::ConcreteGroupItem;
|
2015-07-11 18:37:53 +00:00
|
|
|
};
|
|
|
|
|
2020-02-02 22:32:23 +00:00
|
|
|
class PopupMenuTable : public wxEvtHandler
|
2015-07-11 18:37:53 +00:00
|
|
|
{
|
|
|
|
public:
|
2020-02-05 20:20:08 +00:00
|
|
|
using Entry = PopupMenuTableEntry;
|
|
|
|
|
|
|
|
// Supply a nonempty caption for sub-menu tables
|
2020-02-03 17:26:40 +00:00
|
|
|
PopupMenuTable( const Identifier &id, const TranslatableString &caption = {} )
|
2020-02-05 23:01:28 +00:00
|
|
|
: mId{ id }
|
|
|
|
, mCaption{ caption }
|
2020-02-05 20:20:08 +00:00
|
|
|
{}
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-01-02 02:09:16 +00:00
|
|
|
// Called before the menu items are appended.
|
|
|
|
// Store user data, if needed.
|
|
|
|
virtual void InitUserData(void *pUserData) = 0;
|
|
|
|
|
2015-07-11 18:37:53 +00:00
|
|
|
// Called when the menu is about to pop up.
|
|
|
|
// Your chance to enable and disable items.
|
2020-01-02 02:09:16 +00:00
|
|
|
// Default implementation does nothing.
|
2020-02-05 01:51:29 +00:00
|
|
|
virtual void InitMenu(wxMenu *pMenu);
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
// Called when menu is destroyed.
|
|
|
|
virtual void DestroyMenu() = 0;
|
|
|
|
|
2020-01-02 02:09:16 +00:00
|
|
|
// Optional pUserData gets passed to the InitUserData routines of tables.
|
2015-07-11 18:37:53 +00:00
|
|
|
// No memory management responsibility is assumed by this function.
|
2020-02-05 01:51:29 +00:00
|
|
|
static std::unique_ptr<wxMenu> BuildMenu
|
2015-07-11 18:37:53 +00:00
|
|
|
(wxEvtHandler *pParent, PopupMenuTable *pTable, void *pUserData = NULL);
|
2020-02-02 22:32:23 +00:00
|
|
|
|
2020-02-05 23:01:28 +00:00
|
|
|
const Identifier &Id() const { return mId; }
|
2020-02-05 20:20:08 +00:00
|
|
|
const TranslatableString &Caption() const { return mCaption; }
|
|
|
|
|
2020-02-05 01:51:29 +00:00
|
|
|
// menu must have been built by BuildMenu
|
|
|
|
// More items get added to the end of it
|
|
|
|
static void ExtendMenu( wxMenu &menu, PopupMenuTable &otherTable );
|
2020-02-05 23:01:28 +00:00
|
|
|
|
2020-02-08 18:01:23 +00:00
|
|
|
const std::shared_ptr< Registry::GroupItem > &Get( void *pUserData )
|
2020-02-02 22:32:23 +00:00
|
|
|
{
|
2020-02-08 18:01:23 +00:00
|
|
|
this->InitUserData( pUserData );
|
2020-02-05 23:01:28 +00:00
|
|
|
if (!mTop)
|
2020-02-02 22:32:23 +00:00
|
|
|
Populate();
|
2020-02-05 23:01:28 +00:00
|
|
|
return mTop;
|
2020-02-02 22:32:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-05 01:51:29 +00:00
|
|
|
protected:
|
|
|
|
virtual void Populate() = 0;
|
2020-02-05 23:01:28 +00:00
|
|
|
void Clear() { mTop.reset(); }
|
2020-02-05 01:51:29 +00:00
|
|
|
|
2020-02-06 21:51:54 +00:00
|
|
|
std::shared_ptr< Registry::GroupItem > mTop;
|
2020-02-05 23:01:28 +00:00
|
|
|
std::vector< Registry::GroupItem* > mStack;
|
|
|
|
Identifier mId;
|
2020-02-05 20:20:08 +00:00
|
|
|
TranslatableString mCaption;
|
2015-07-11 18:37:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
The following macros make it easy to attach a popup menu to a window.
|
|
|
|
|
|
|
|
Exmple of usage:
|
|
|
|
|
|
|
|
In class MyTable (maybe in the private section),
|
|
|
|
which inherits from PopupMenuTable,
|
|
|
|
|
|
|
|
DECLARE_POPUP_MENU(MyTable);
|
2020-01-02 02:09:16 +00:00
|
|
|
virtual void InitUserData(void *pUserData);
|
2020-02-05 01:51:29 +00:00
|
|
|
virtual void InitMenu(wxMenu *pMenu);
|
2015-07-11 18:37:53 +00:00
|
|
|
virtual void DestroyMenu();
|
|
|
|
|
|
|
|
Then in MyTable.cpp,
|
|
|
|
|
2020-01-02 02:09:16 +00:00
|
|
|
void MyTable::InitUserData(void *pUserData)
|
2015-07-11 18:37:53 +00:00
|
|
|
{
|
2020-02-02 21:52:09 +00:00
|
|
|
// Remember pData
|
2015-07-11 18:37:53 +00:00
|
|
|
auto pData = static_cast<MyData*>(pUserData);
|
2020-01-02 02:09:16 +00:00
|
|
|
}
|
|
|
|
|
2020-02-05 01:51:29 +00:00
|
|
|
void MyTable::InitMenu(wxMenu *pMenu)
|
2020-01-02 02:09:16 +00:00
|
|
|
{
|
2020-02-02 21:52:09 +00:00
|
|
|
// enable or disable menu items
|
2015-07-11 18:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MyTable::DestroyMenu()
|
|
|
|
{
|
2020-02-02 21:52:09 +00:00
|
|
|
// Do cleanup
|
2015-07-11 18:37:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BEGIN_POPUP_MENU(MyTable)
|
|
|
|
// This is inside a function and can contain arbitrary code. But usually
|
|
|
|
// you only need a sequence of macro calls:
|
|
|
|
|
2020-02-03 20:33:48 +00:00
|
|
|
POPUP_MENU_ITEM("Cut", OnCutSelectedTextID, XO("Cu&t"), OnCutSelectedText)
|
2015-07-11 18:37:53 +00:00
|
|
|
// etc.
|
|
|
|
|
|
|
|
END_POPUP_MENU()
|
|
|
|
|
|
|
|
where OnCutSelectedText is a (maybe private) member function of MyTable.
|
|
|
|
|
|
|
|
Elswhere,
|
|
|
|
|
|
|
|
MyTable myTable;
|
|
|
|
MyData data;
|
|
|
|
auto pMenu = PopupMenuTable::BuildMenu(pParent, &myTable, &data);
|
|
|
|
|
|
|
|
// Optionally:
|
|
|
|
OtherTable otherTable;
|
2020-02-05 01:51:29 +00:00
|
|
|
PopupMenuTable::ExtendMenu( *pMenu, otherTable );
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
pParent->PopupMenu(pMenu.get(), event.m_x, event.m_y);
|
|
|
|
|
|
|
|
That's all!
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define DECLARE_POPUP_MENU(HandlerClass) \
|
2018-01-09 13:35:56 +00:00
|
|
|
void Populate() override;
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
// begins function
|
|
|
|
#define BEGIN_POPUP_MENU(HandlerClass) \
|
|
|
|
void HandlerClass::Populate() { \
|
2020-02-05 23:01:28 +00:00
|
|
|
using My = HandlerClass; \
|
|
|
|
mTop = std::make_shared< PopupSubMenu >( \
|
|
|
|
Id(), Caption(), *this ); \
|
|
|
|
mStack.clear(); \
|
|
|
|
mStack.push_back( mTop.get() );
|
|
|
|
|
|
|
|
#define POPUP_MENU_APPEND(stringId, type, id, string, memFn) \
|
|
|
|
mStack.back()->items.push_back( std::make_unique<Entry>( \
|
|
|
|
Identifier{ stringId }, \
|
2015-07-11 18:37:53 +00:00
|
|
|
type, \
|
|
|
|
id, \
|
|
|
|
string, \
|
2020-02-05 23:01:28 +00:00
|
|
|
memFn \
|
|
|
|
) );
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-03 20:33:48 +00:00
|
|
|
#define POPUP_MENU_APPEND_ITEM(stringId, type, id, string, memFn) \
|
|
|
|
POPUP_MENU_APPEND( stringId, \
|
2015-07-11 18:37:53 +00:00
|
|
|
type, \
|
|
|
|
id, \
|
|
|
|
string, \
|
2020-02-05 23:01:28 +00:00
|
|
|
(wxCommandEventFunction) (&My::memFn) )
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-03 20:33:48 +00:00
|
|
|
#define POPUP_MENU_ITEM(stringId, id, string, memFn) \
|
|
|
|
POPUP_MENU_APPEND_ITEM(stringId, Entry::Item, id, string, memFn);
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-03 20:33:48 +00:00
|
|
|
#define POPUP_MENU_RADIO_ITEM(stringId, id, string, memFn) \
|
|
|
|
POPUP_MENU_APPEND_ITEM(stringId, Entry::RadioItem, id, string, memFn);
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-03 20:33:48 +00:00
|
|
|
#define POPUP_MENU_CHECK_ITEM(stringId, id, string, memFn) \
|
|
|
|
POPUP_MENU_APPEND_ITEM(stringId, Entry::CheckItem, id, string, memFn);
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
// classname names a class that derives from MenuTable and defines Instance()
|
2020-02-08 18:01:23 +00:00
|
|
|
#define POPUP_MENU_SUB_MENU(stringId, classname, pUserData ) \
|
2020-02-05 23:01:28 +00:00
|
|
|
mStack.back()->items.push_back( \
|
2020-02-08 18:01:23 +00:00
|
|
|
Registry::Shared( classname::Instance().Get( pUserData ) ) );
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-05 01:51:29 +00:00
|
|
|
#define BEGIN_POPUP_MENU_SECTION( name ) \
|
2020-02-05 23:01:28 +00:00
|
|
|
{ auto uSection = std::make_unique< PopupMenuSection >( \
|
|
|
|
Identifier{ name } ); \
|
|
|
|
auto section = uSection.get(); \
|
|
|
|
mStack.back()->items.push_back( std::move( uSection ) ); \
|
|
|
|
mStack.push_back( section ); \
|
|
|
|
}
|
2015-07-11 18:37:53 +00:00
|
|
|
|
2020-02-05 23:01:28 +00:00
|
|
|
#define END_POPUP_MENU_SECTION() mStack.pop_back();
|
2020-02-05 01:51:29 +00:00
|
|
|
|
2015-07-11 18:37:53 +00:00
|
|
|
// ends function
|
2020-02-05 23:01:28 +00:00
|
|
|
#define END_POPUP_MENU() }
|
2015-07-11 18:37:53 +00:00
|
|
|
|
|
|
|
#endif
|