📄 menu.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/carbon/menu.cpp
// Purpose: wxMenu, wxMenuBar, wxMenuItem
// Author: Stefan Csomor
// Modified by:
// Created: 1998-01-01
// RCS-ID: $Id: menu.cpp,v 1.92 2006/06/19 07:12:37 ABX Exp $
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// headers & declarations
// ============================================================================
// wxWidgets headers
// -----------------
#include "wx/wxprec.h"
#include "wx/menu.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/window.h"
#include "wx/frame.h"
#include "wx/menuitem.h"
#endif
#include "wx/mac/uma.h"
// other standard headers
// ----------------------
#include <string.h>
IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
// the (popup) menu title has this special id
static const int idMenuTitle = -3;
const short kwxMacMenuBarResource = 1 ;
const short kwxMacAppleMenuId = 1 ;
// Find an item given the Macintosh Menu Reference
WX_DECLARE_HASH_MAP(MenuRef, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
static MacMenuMap wxWinMacMenuList;
wxMenu *wxFindMenuFromMacMenu(MenuRef inMenuRef)
{
MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
return (node == wxWinMacMenuList.end()) ? NULL : node->second;
}
void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu) ;
void wxAssociateMenuWithMacMenu(MenuRef inMenuRef, wxMenu *menu)
{
// adding NULL MenuRef is (first) surely a result of an error and
// (secondly) breaks menu command processing
wxCHECK_RET( inMenuRef != (MenuRef) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
wxWinMacMenuList[inMenuRef] = menu;
}
void wxRemoveMacMenuAssociation(wxMenu *menu) ;
void wxRemoveMacMenuAssociation(wxMenu *menu)
{
// iterate over all the elements in the class
MacMenuMap::iterator it;
for ( it = wxWinMacMenuList.begin(); it != wxWinMacMenuList.end(); ++it )
{
if ( it->second == menu )
{
wxWinMacMenuList.erase(it);
break;
}
}
}
// ============================================================================
// implementation
// ============================================================================
static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ;
static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win );
// Menus
// Construct a menu with optional title (then use append)
#ifdef __DARWIN__
short wxMenu::s_macNextMenuId = 3 ;
#else
short wxMenu::s_macNextMenuId = 2 ;
#endif
static
wxMenu *
_wxMenuAt(const wxMenuList &menuList, size_t pos)
{
wxMenuList::compatibility_iterator menuIter = menuList.GetFirst();
while (pos-- > 0)
menuIter = menuIter->GetNext();
return menuIter->GetData() ;
}
void wxMenu::Init()
{
m_doBreak = false;
m_startRadioGroup = -1;
// create the menu
m_macMenuId = s_macNextMenuId++;
m_hMenu = UMANewMenu(m_macMenuId, m_title, wxFont::GetDefaultEncoding() );
if ( !m_hMenu )
{
wxLogLastError(wxT("UMANewMenu failed"));
}
wxAssociateMenuWithMacMenu( (MenuRef)m_hMenu , this ) ;
// if we have a title, insert it in the beginning of the menu
if ( !m_title.empty() )
{
Append(idMenuTitle, m_title) ;
AppendSeparator() ;
}
}
wxMenu::~wxMenu()
{
wxRemoveMacMenuAssociation( this ) ;
if (MAC_WXHMENU(m_hMenu))
::DisposeMenu(MAC_WXHMENU(m_hMenu));
}
void wxMenu::Break()
{
// not available on the mac platform
}
void wxMenu::Attach(wxMenuBarBase *menubar)
{
wxMenuBase::Attach(menubar);
EndRadioGroup();
}
// function appends a new item or submenu to the menu
// append a new item or submenu to the menu
bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
{
wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
if ( pItem->IsSeparator() )
{
if ( pos == (size_t)-1 )
MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-");
else
MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos);
}
else
{
wxMenu *pSubMenu = pItem->GetSubMenu() ;
if ( pSubMenu != NULL )
{
wxASSERT_MSG( pSubMenu->m_hMenu != NULL , wxT("invalid submenu added"));
pSubMenu->m_menuParent = this ;
if (wxMenuBar::MacGetInstalledMenuBar() == GetMenuBar())
pSubMenu->MacBeforeDisplay( true ) ;
if ( pos == (size_t)-1 )
UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), wxStripMenuCodes(pItem->GetText()), wxFont::GetDefaultEncoding(), pSubMenu->m_macMenuId);
else
UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), wxStripMenuCodes(pItem->GetText()), wxFont::GetDefaultEncoding(), pos, pSubMenu->m_macMenuId);
pItem->UpdateItemBitmap() ;
pItem->UpdateItemStatus() ;
}
else
{
if ( pos == (size_t)-1 )
{
UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), wxT("a") , wxFont::GetDefaultEncoding() );
pos = CountMenuItems(MAC_WXHMENU(m_hMenu)) ;
}
else
{
// MacOS counts menu items from 1 and inserts after, therefore having the
// same effect as wx 0 based and inserting before, we must correct pos
// after however for updates to be correct
UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), wxT("a"), wxFont::GetDefaultEncoding(), pos);
pos += 1 ;
}
SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , wxIdToMacCommand ( pItem->GetId() ) ) ;
SetMenuItemRefCon( MAC_WXHMENU(m_hMenu) , pos , (UInt32) pItem ) ;
pItem->UpdateItemText() ;
pItem->UpdateItemBitmap() ;
pItem->UpdateItemStatus() ;
if ( pItem->GetId() == idMenuTitle )
UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , pos , false ) ;
}
}
// if we're already attached to the menubar, we must update it
if ( IsAttached() && GetMenuBar()->IsAttached() )
GetMenuBar()->Refresh();
return true ;
}
void wxMenu::EndRadioGroup()
{
// we're not inside a radio group any longer
m_startRadioGroup = -1;
}
wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
{
wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
bool check = false;
if ( item->GetKind() == wxITEM_RADIO )
{
int count = GetMenuItemCount();
if ( m_startRadioGroup == -1 )
{
// start a new radio group
m_startRadioGroup = count;
// for now it has just one element
item->SetAsRadioGroupStart();
item->SetRadioGroupEnd(m_startRadioGroup);
// ensure that we have a checked item in the radio group
check = true;
}
else // extend the current radio group
{
// we need to update its end item
item->SetRadioGroupStart(m_startRadioGroup);
wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
if ( node )
{
node->GetData()->SetRadioGroupEnd(count);
}
else
{
wxFAIL_MSG( _T("where is the radio group start item?") );
}
}
}
else // not a radio item
{
EndRadioGroup();
}
if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
return NULL;
if ( check )
// check the item initially
item->Check(true);
return item;
}
wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
{
if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
return item;
return NULL;
}
wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
{
// we need to find the items position in the child list
size_t pos;
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
for ( pos = 0; node; pos++ )
{
if ( node->GetData() == item )
break;
node = node->GetNext();
}
// DoRemove() (unlike Remove) can only be called for existing item!
wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1);
if ( IsAttached() && GetMenuBar()->IsAttached() )
// otherwise, the change won't be visible
GetMenuBar()->Refresh();
// and from internal data structures
return wxMenuBase::DoRemove(item);
}
void wxMenu::SetTitle(const wxString& label)
{
m_title = label ;
UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label , wxFont::GetDefaultEncoding() ) ;
}
bool wxMenu::ProcessCommand(wxCommandEvent & event)
{
bool processed = false;
// Try the menu's event handler
if ( /* !processed && */ GetEventHandler())
processed = GetEventHandler()->ProcessEvent(event);
// Try the window the menu was popped up from
// (and up through the hierarchy)
wxWindow *win = GetInvokingWindow();
if ( !processed && win )
processed = win->GetEventHandler()->ProcessEvent(event);
return processed;
}
// ---------------------------------------------------------------------------
// other
// ---------------------------------------------------------------------------
wxWindow *wxMenu::GetWindow() const
{
if ( m_invokingWindow != NULL )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -