📄 commandmanager.cpp
字号:
/********************************************************************** Audacity: A Digital Audio Editor CommandManager.cpp Brian Gunlogson Dominic Mazzoni See CommandManager.h for an overview of this class.**********************************************************************/#include "../Audacity.h"#include <wx/defs.h>#include <wx/hash.h>#include <wx/intl.h>#include <wx/msgdlg.h>#include <wx/log.h>#include "../Prefs.h"#include "../Project.h"#include "CommandManager.h"#include "Keyboard.h"#include "../effects/Effect.h"// On wxGTK, there may be many many many plugins, but the menus don't automatically// allow for scrolling, so we build sub-menus. If the menu gets longer than// MAX_MENU_LEN, we put things in submenus that have MAX_SUBMENU_LEN items in them.// #ifdef __WXGTK__#define MAX_MENU_LEN 20#define MAX_SUBMENU_LEN 15#else#define MAX_MENU_LEN 1000#define MAX_SUBMENU_LEN 1000#endif////// Standard Constructor///CommandManager::CommandManager(): mCurrentID(0), mHiddenID(0), mCurrentMenu(NULL), mDefaultFlags(0), mDefaultMask(0){}////// Class Destructor. Includes PurgeData, which removes/// menubarsCommandManager::~CommandManager(){ //WARNING: This removes menubars that could still be assigned to windows! PurgeData();}void CommandManager::PurgeData(){ // Delete callback functors BEFORE clearing mCommandList! // These are the items created within 'FN()' size_t i; CommandFunctor * pCallback = NULL; for(i=0; i<mCommandList.GetCount(); i++) { CommandListEntry *tmpEntry = mCommandList[i]; // JKC: We only want to delete each callbacks once. // AddItemList() may have inserted the same callback // several times over. if( tmpEntry->callback != pCallback ) { pCallback = tmpEntry->callback; delete pCallback; } } // mCommandList contains pointers to CommandListEntrys // mMenuBarList contains pointers to MenuBarListEntrys. // mSubMenuList contains pointers to SubMenuListEntrys WX_CLEAR_ARRAY( mCommandList ); WX_CLEAR_ARRAY( mMenuBarList ); WX_CLEAR_ARRAY( mSubMenuList ); mCommandNameHash.clear(); mCommandKeyHash.clear(); mCommandIDHash.clear(); mCurrentMenu = NULL; mCurrentID = 0;}////// Makes a new menubar for placement on the top of a project/// Names it according to the passed-in string argument.////// If the menubar already exists, simply returns it.wxMenuBar *CommandManager::AddMenuBar(wxString sMenu){ wxMenuBar *menuBar = GetMenuBar(sMenu); if (menuBar) return menuBar; MenuBarListEntry *tmpEntry = new MenuBarListEntry; tmpEntry->menubar = new wxMenuBar(); tmpEntry->name = sMenu; mMenuBarList.Add(tmpEntry); return tmpEntry->menubar;}////// Retrieves the menubar based on the name given in AddMenuBar(name) ///wxMenuBar * CommandManager::GetMenuBar(wxString sMenu){ for(unsigned int i = 0; i < mMenuBarList.GetCount(); i++) { if(!mMenuBarList[i]->name.Cmp(sMenu)) return mMenuBarList[i]->menubar; } return NULL;}////// Retrieve the 'current' menubar; either NULL or the/// last on in the mMenuBarList.wxMenuBar * CommandManager::CurrentMenuBar(){ if(mMenuBarList.IsEmpty()) return NULL; return mMenuBarList[mMenuBarList.GetCount()-1]->menubar;}////// This makes a new menu and adds it to the 'CurrentMenuBar'////// If the menu already exists, all of the items in it are/// cleared instead.///void CommandManager::BeginMenu(wxString tName){ wxMenu *tmpMenu = new wxMenu(); mCurrentMenu = tmpMenu; CurrentMenuBar()->Append(mCurrentMenu, tName);}////// This ends a menu by setting the pointer to it/// to NULL. It is still attached to the CurrentMenuBar()void CommandManager::EndMenu(){ mCurrentMenu = NULL;}////// This starts a new submenu, and names it according to/// the function's argument.wxMenu* CommandManager::BeginSubMenu(wxString tName){ SubMenuListEntry *tmpEntry = new SubMenuListEntry; tmpEntry->menu = new wxMenu(); tmpEntry->name = tName; mSubMenuList.Add(tmpEntry); return(tmpEntry->menu);}////// This function is called after the final item of a SUBmenu is added./// Submenu items are added just like regular menu items; they just happen/// after BeginSubMenu() is called but before EndSubMenu() is called.void CommandManager::EndSubMenu(){ size_t submenu_count = mSubMenuList.GetCount()-1; //Save the submenu's information SubMenuListEntry *tmpSubMenu = mSubMenuList[submenu_count]; //Pop off the new submenu so CurrentMenu returns the parent of the submenu mSubMenuList.RemoveAt(submenu_count); //Add the submenu to the current menu CurrentMenu()->Append(0, tmpSubMenu->name, tmpSubMenu->menu, tmpSubMenu->name); delete tmpSubMenu;}////// This returns the 'Current' Submenu, which is the one at the/// end of the mSubMenuList (or NULL, if it doesn't exist).wxMenu * CommandManager::CurrentSubMenu(){ if(mSubMenuList.IsEmpty()) return NULL; return mSubMenuList[mSubMenuList.GetCount()-1]->menu;}////// This returns the current menu that we're appending to - note that/// it could be a submenu if BeginSubMenu was called and we haven't/// reached EndSubMenu yet.wxMenu * CommandManager::CurrentMenu(){ if(!mCurrentMenu) return NULL; wxMenu * tmpCurrentSubMenu = CurrentSubMenu(); if(!tmpCurrentSubMenu) { return mCurrentMenu; } return tmpCurrentSubMenu;}////// Add a menu item to the current menu. When the user selects it, the/// given functor will be calledvoid CommandManager::AddItem(wxString name, wxString label, CommandFunctor *callback){ int ID = NewIdentifier(name, label, CurrentMenu(), callback, false, 0, 0); // Replace the accel key with the one from the preferences label = label.BeforeFirst(wxT('\t')); // This is a very weird hack. Under GTK, menu labels are totally // linked to accelerators the first time you create a menu item // with that label and can't be changed. This causes all sorts of // problems. As a workaround, we create each menu item with a // made-up name (just an ID number string) but with the accelerator // we want, then immediately change the label to the correct string. // -DMM mHiddenID++; wxString dummy, newLabel; dummy.Printf(wxT("%s%08d"), label.c_str(), mHiddenID); newLabel = label; bool shortcut = false; if (mCommandIDHash[ID]->key.Length() > 0) shortcut = true; // Mac OS X fixes #ifdef __WXMAC__ if (newLabel.Length() > 0 && newLabel[0] == wxT('&')) newLabel = newLabel.Right(newLabel.Length()-1); if (shortcut == true && (mCommandIDHash[ID]->key.Length() < 5 || mCommandIDHash[ID]->key.Left(5) != wxT("Ctrl+"))) shortcut = false; #endif if (shortcut) { dummy = dummy + wxT("\t") + mCommandIDHash[ID]->key; newLabel = newLabel + wxT("\t") + mCommandIDHash[ID]->key; } CurrentMenu()->Append(ID, dummy); CurrentMenu()->SetLabel(ID, newLabel);}////// Add a list of menu items to the current menu. When the user selects any/// one of these, the given functor will be called/// with its position in the list as the index number./// When you call Enable on this command name, it will enable or disable/// all of the items at once.void CommandManager::AddItemList(wxString name, wxArrayString labels, CommandFunctor *callback, bool plugins /*= false*/){ unsigned int i; #ifndef __WXGTK__ plugins = false; #endif if (CurrentMenu()->GetMenuItemCount() + labels.GetCount() < MAX_MENU_LEN) plugins = false; if (!plugins) { for(i=0; i<labels.GetCount(); i++) { int ID = NewIdentifier(name, labels[i], CurrentMenu(), callback, true, i, labels.GetCount()); CurrentMenu()->Append(ID, labels[i]); } return; } wxString label; unsigned int effLen = labels.GetCount(); int listnum = 1; int tmpmax = MAX_SUBMENU_LEN < effLen? MAX_SUBMENU_LEN: effLen; //The first submenu starts at 1. BeginSubMenu(wxString::Format(_("Plugins 1 to %i"), tmpmax)); for(i=0; i<effLen; i++) { int ID = NewIdentifier(name, labels[i], CurrentMenu(), callback, true, i, effLen); CurrentMenu()->Append(ID, labels[i]); if(((i+1) % MAX_SUBMENU_LEN) == 0 && i != (effLen - 1)) { EndSubMenu(); listnum++; //This label the plugins by number in the submenu title (1 to 15, 15 to 30, etc.) tmpmax = i + MAX_SUBMENU_LEN < effLen? 1 + i + MAX_SUBMENU_LEN: effLen; BeginSubMenu(wxString::Format(_("Plugins %i to %i"),i+2,tmpmax)); } } EndSubMenu();}////// Add a command that doesn't appear in a menu. When the key is pressed, the/// given function pointer will be called (via the CommandManagerListener)void CommandManager::AddCommand(wxString name, wxString label, CommandFunctor *callback){ NewIdentifier(name, label, NULL, callback, false, 0, 0);}void CommandManager::AddSeparator(){ CurrentMenu()->AppendSeparator();}int CommandManager::NextIdentifier(int ID){ ID++; //Skip the reserved identifiers used by wxWindows if((ID >= wxID_LOWEST) && (ID <= wxID_HIGHEST)) ID = wxID_HIGHEST+1; return ID;}///Given all of the information for a command, comes up with a new unique///ID, adds it to a list, and returns the ID.///WARNING: Does this conflict with the identifiers set for controls/windows?///If it does, a workaround may be to keep controls below wxID_LOWEST///and keep menus above wxID_HIGHESTint CommandManager::NewIdentifier(wxString name, wxString label, wxMenu *menu, CommandFunctor *callback, bool multi, int index, int count){ CommandListEntry *tmpEntry = new CommandListEntry; // wxMac 2.5 and higher will do special things with the // Preferences, Exit (Quit), and About menu items, // if we give them the right IDs. // Otherwise we just pick increasing ID numbers for each new // command. Note that the name string we are comparing // ("About", "Preferences") is the internal command name
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -