This commit is huge but there are no non-white-space changes in it. Some files containing third-party sources (src/msw/wince/time.cpp, src/x11/pango*.cpp) were left unchanged. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61724 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
421 lines
12 KiB
C++
421 lines
12 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/osx/carbon/menu.cpp
|
|
// Purpose: wxMenu, wxMenuBar, wxMenuItem
|
|
// Author: Stefan Csomor
|
|
// Modified by:
|
|
// Created: 1998-01-01
|
|
// RCS-ID: $Id$
|
|
// 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/frame.h"
|
|
#include "wx/menuitem.h"
|
|
#endif
|
|
|
|
#include "wx/osx/private.h"
|
|
#include "wx/stockitem.h"
|
|
|
|
// other standard headers
|
|
// ----------------------
|
|
#include <string.h>
|
|
|
|
// under carbon there's no such thing as a MenuItemRef, everything is done
|
|
// on the 'parent' menu via index APIs (first line having index 1 !)
|
|
// so to make things still work, we store the wxMenuItemImpl instance as a
|
|
// RefCon at the respective menu line
|
|
|
|
class wxMenuItemCarbonImpl : public wxMenuItemImpl
|
|
{
|
|
public :
|
|
wxMenuItemCarbonImpl( wxMenuItem* peer ) : wxMenuItemImpl(peer)
|
|
{
|
|
// the parent menu ref is only set, once the item has been attached
|
|
m_parentMenuRef = NULL;
|
|
}
|
|
|
|
~wxMenuItemCarbonImpl();
|
|
|
|
void SetBitmap( const wxBitmap& bitmap )
|
|
{
|
|
MenuItemIndex i = FindMenuItemIndex() ;
|
|
if ( i > 0 )
|
|
{
|
|
if ( bitmap.Ok() )
|
|
{
|
|
#if wxUSE_BMPBUTTON
|
|
ControlButtonContentInfo info ;
|
|
wxMacCreateBitmapButton( &info , bitmap ) ;
|
|
if ( info.contentType != kControlNoContent )
|
|
{
|
|
if ( info.contentType == kControlContentIconRef )
|
|
SetMenuItemIconHandle( m_parentMenuRef, i ,
|
|
kMenuIconRefType , (Handle) info.u.iconRef ) ;
|
|
else if ( info.contentType == kControlContentCGImageRef )
|
|
SetMenuItemIconHandle( m_parentMenuRef, i ,
|
|
kMenuCGImageRefType , (Handle) info.u.imageRef ) ;
|
|
}
|
|
wxMacReleaseBitmapButton( &info ) ;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void Enable( bool enable )
|
|
{
|
|
MenuItemIndex i = FindMenuItemIndex() ;
|
|
if ( i > 0 )
|
|
{
|
|
|
|
if ( GetWXPeer()->GetId() == wxApp::s_macPreferencesMenuItemId)
|
|
{
|
|
if ( enable )
|
|
EnableMenuCommand( NULL , kHICommandPreferences ) ;
|
|
else
|
|
DisableMenuCommand( NULL , kHICommandPreferences ) ;
|
|
}
|
|
else if ( GetWXPeer()->GetId() == wxApp::s_macExitMenuItemId)
|
|
{
|
|
if ( enable )
|
|
EnableMenuCommand( NULL , kHICommandQuit ) ;
|
|
else
|
|
DisableMenuCommand( NULL , kHICommandQuit ) ;
|
|
}
|
|
|
|
if ( enable )
|
|
EnableMenuItem(m_parentMenuRef , i);
|
|
else
|
|
DisableMenuItem(m_parentMenuRef , i);
|
|
|
|
if ( GetWXPeer()->IsSubMenu() )
|
|
{
|
|
UMAEnableMenuItem( GetWXPeer()->GetSubMenu()->GetHMenu() , 0 , enable ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Check( bool check )
|
|
{
|
|
MenuItemIndex i = FindMenuItemIndex() ;
|
|
if ( i > 0 )
|
|
{
|
|
if ( check )
|
|
::SetItemMark( m_parentMenuRef, i, 0x12 ) ; // checkmark
|
|
else
|
|
::SetItemMark( m_parentMenuRef, i, 0 ) ; // no mark
|
|
}
|
|
}
|
|
|
|
void Hide( bool hide )
|
|
{
|
|
MenuItemIndex i = FindMenuItemIndex() ;
|
|
if ( i > 0 )
|
|
{
|
|
if ( hide )
|
|
ChangeMenuItemAttributes( m_parentMenuRef, i, kMenuItemAttrHidden, 0 );
|
|
else
|
|
ChangeMenuItemAttributes( m_parentMenuRef, i, 0 , kMenuItemAttrHidden );
|
|
}
|
|
}
|
|
|
|
void SetLabel( const wxString& text, wxAcceleratorEntry *entry )
|
|
{
|
|
MenuItemIndex i = FindMenuItemIndex() ;
|
|
if ( i > 0 )
|
|
{
|
|
SetMenuItemTextWithCFString( m_parentMenuRef, i, wxCFStringRef(text));
|
|
UMASetMenuItemShortcut( m_parentMenuRef, i , entry ) ;
|
|
}
|
|
}
|
|
|
|
void * GetHMenuItem() { return NULL; }
|
|
|
|
// Carbon Only
|
|
|
|
void AttachToParent( MenuRef parentMenuRef, MenuItemIndex index )
|
|
{
|
|
m_parentMenuRef = parentMenuRef;
|
|
if ( m_parentMenuRef && index > 0 )
|
|
SetMenuItemRefCon( m_parentMenuRef, index, (URefCon) this );
|
|
}
|
|
|
|
MenuItemIndex FindMenuItemIndex()
|
|
{
|
|
MenuItemIndex hit = 0 ;
|
|
if ( m_parentMenuRef )
|
|
{
|
|
for ( MenuItemIndex i = 1 ; i <= CountMenuItems(m_parentMenuRef) ; ++i )
|
|
{
|
|
URefCon storedRef = 0;
|
|
GetMenuItemRefCon(m_parentMenuRef, i, &storedRef );
|
|
if ( storedRef == (URefCon) this )
|
|
{
|
|
hit = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return hit;
|
|
}
|
|
protected :
|
|
MenuRef m_parentMenuRef;
|
|
} ;
|
|
|
|
//
|
|
// wxMenuImpl
|
|
//
|
|
|
|
class wxMenuCarbonImpl : public wxMenuImpl
|
|
{
|
|
public :
|
|
wxMenuCarbonImpl( wxMenu* peer , MenuRef menu) : wxMenuImpl(peer), m_osxMenu(menu)
|
|
{
|
|
}
|
|
|
|
virtual ~wxMenuCarbonImpl();
|
|
|
|
virtual void InsertOrAppend(wxMenuItem *pItem, size_t pos)
|
|
{
|
|
// 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
|
|
|
|
MenuItemIndex index = pos;
|
|
if ( pos == (size_t) -1 )
|
|
index = CountMenuItems(m_osxMenu);
|
|
|
|
if ( pItem->IsSeparator() )
|
|
{
|
|
InsertMenuItemTextWithCFString( m_osxMenu, CFSTR(""), index, kMenuItemAttrSeparator, 0);
|
|
// now switch to the Carbon 1 based counting
|
|
index += 1 ;
|
|
}
|
|
else
|
|
{
|
|
InsertMenuItemTextWithCFString( m_osxMenu, CFSTR("placeholder"), index, 0, 0 );
|
|
|
|
// now switch to the Carbon 1 based counting
|
|
index += 1 ;
|
|
if ( pItem->IsSubMenu() )
|
|
{
|
|
MenuRef submenu = pItem->GetSubMenu()->GetHMenu();
|
|
SetMenuItemHierarchicalMenu(m_osxMenu, index, submenu);
|
|
// carbon is using the title of the submenu, eg in the menubar
|
|
SetMenuTitleWithCFString(submenu, wxCFStringRef(pItem->GetItemLabelText()));
|
|
}
|
|
else
|
|
{
|
|
SetMenuItemCommandID( m_osxMenu, index , wxIdToMacCommand(pItem->GetId()) ) ;
|
|
}
|
|
}
|
|
|
|
wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
|
|
impl->AttachToParent( m_osxMenu, index );
|
|
// only now can all settings be updated correctly
|
|
pItem->UpdateItemText();
|
|
pItem->UpdateItemStatus();
|
|
pItem->UpdateItemBitmap();
|
|
}
|
|
|
|
virtual void Remove( wxMenuItem *pItem )
|
|
{
|
|
wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
|
|
if ( impl )
|
|
{
|
|
MenuItemIndex i = impl->FindMenuItemIndex();
|
|
if ( i > 0 )
|
|
{
|
|
DeleteMenuItem(m_osxMenu , i);
|
|
impl->AttachToParent( NULL, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void MakeRoot()
|
|
{
|
|
SetRootMenu( m_osxMenu );
|
|
}
|
|
|
|
virtual void SetTitle( const wxString& text )
|
|
{
|
|
SetMenuTitleWithCFString(m_osxMenu, wxCFStringRef(text));
|
|
}
|
|
|
|
WXHMENU GetHMenu() { return m_osxMenu; }
|
|
|
|
virtual void PopUp( wxWindow *WXUNUSED(win), int x, int y )
|
|
{
|
|
long menuResult = ::PopUpMenuSelect(m_osxMenu, y, x, 0) ;
|
|
if ( HiWord(menuResult) != 0 )
|
|
{
|
|
MenuCommand macid;
|
|
GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &macid );
|
|
int id = wxMacCommandToId( macid );
|
|
wxMenuItem* item = NULL ;
|
|
wxMenu* realmenu ;
|
|
item = m_peer->FindItem( id, &realmenu ) ;
|
|
if ( item )
|
|
{
|
|
m_peer->HandleCommandProcess(item, NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
static wxMenuImpl* Create( wxMenu* peer, const wxString& title );
|
|
static wxMenuImpl* CreateRootMenu( wxMenu* peer );
|
|
protected :
|
|
wxCFRef<MenuRef> m_osxMenu;
|
|
} ;
|
|
|
|
// static const short kwxMacAppleMenuId = 1 ;
|
|
|
|
// Find an item given the Macintosh Menu Reference
|
|
|
|
WX_DECLARE_HASH_MAP(WXHMENU, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
|
|
|
|
static MacMenuMap wxWinMacMenuList;
|
|
|
|
wxMenu *wxFindMenuFromMacMenu(WXHMENU inMenuRef)
|
|
{
|
|
MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
|
|
|
|
return (node == wxWinMacMenuList.end()) ? NULL : node->second;
|
|
}
|
|
|
|
void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu) ;
|
|
void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu)
|
|
{
|
|
// adding NULL MenuRef is (first) surely a result of an error and
|
|
// (secondly) breaks menu command processing
|
|
wxCHECK_RET( inMenuRef != (WXHMENU) 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
wxMenuCarbonImpl::~wxMenuCarbonImpl()
|
|
{
|
|
wxRemoveMacMenuAssociation( GetWXPeer() );
|
|
}
|
|
|
|
wxMenuImpl* wxMenuImpl::Create( wxMenu* peer, const wxString& title )
|
|
{
|
|
// create the menu
|
|
static SInt16 s_macNextMenuId = 3;
|
|
WXHMENU menu = NULL;
|
|
CreateNewMenu( s_macNextMenuId++ , 0 , &menu ) ;
|
|
if ( !menu )
|
|
{
|
|
wxLogLastError(wxT("CreateNewMenu failed"));
|
|
return NULL;
|
|
}
|
|
|
|
wxMenuImpl* c = new wxMenuCarbonImpl( peer, menu );
|
|
c->SetTitle(title);
|
|
wxAssociateMenuWithMacMenu( menu , peer ) ;
|
|
return c;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
wxMenuItemCarbonImpl::~wxMenuItemCarbonImpl()
|
|
{
|
|
}
|
|
|
|
|
|
wxMenuItemImpl* wxMenuItemImpl::Create( wxMenuItem* peer,
|
|
wxMenu * WXUNUSED(pParentMenu),
|
|
int WXUNUSED(id),
|
|
const wxString& WXUNUSED(text),
|
|
wxAcceleratorEntry *WXUNUSED(entry),
|
|
const wxString& WXUNUSED(strHelp),
|
|
wxItemKind WXUNUSED(kind),
|
|
wxMenu *WXUNUSED(pSubMenu) )
|
|
{
|
|
wxMenuItemImpl* c = NULL;
|
|
|
|
c = new wxMenuItemCarbonImpl( peer );
|
|
return c;
|
|
}
|
|
|
|
void wxInsertMenuItemsInMenu(wxMenu* menu, MenuRef wm, MenuItemIndex insertAfter)
|
|
{
|
|
wxMenuItemList::compatibility_iterator node;
|
|
wxMenuItem *item;
|
|
wxMenu *subMenu = NULL ;
|
|
bool newItems = false;
|
|
|
|
for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
|
|
{
|
|
item = (wxMenuItem *)node->GetData();
|
|
subMenu = item->GetSubMenu() ;
|
|
if (subMenu)
|
|
{
|
|
wxInsertMenuItemsInMenu(subMenu, (MenuRef)subMenu->GetHMenu(), 0);
|
|
}
|
|
if ( item->IsSeparator() )
|
|
{
|
|
if ( wm && newItems)
|
|
InsertMenuItemTextWithCFString( wm,
|
|
CFSTR(""), insertAfter, kMenuItemAttrSeparator, 0);
|
|
|
|
newItems = false;
|
|
}
|
|
else
|
|
{
|
|
wxAcceleratorEntry*
|
|
entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
|
|
|
|
MenuItemIndex winListPos = (MenuItemIndex)-1;
|
|
OSStatus err = GetIndMenuItemWithCommandID(wm,
|
|
wxIdToMacCommand ( item->GetId() ), 1, NULL, &winListPos);
|
|
|
|
if ( wm && err == menuItemNotFoundErr )
|
|
{
|
|
// NB: the only way to determine whether or not we should add
|
|
// a separator is to know if we've added menu items to the menu
|
|
// before the separator.
|
|
newItems = true;
|
|
UMAInsertMenuItem(wm, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter, entry);
|
|
SetMenuItemCommandID( wm , insertAfter+1 , wxIdToMacCommand ( item->GetId() ) ) ;
|
|
SetMenuItemRefCon( wm , insertAfter+1 , (URefCon) item ) ;
|
|
}
|
|
|
|
delete entry ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|