2007-07-05 07:31:52 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* $RCSfile: salmenu.cxx,v $
|
2008-08-18 12:29:30 +00:00
|
|
|
* $Revision: 1.14 $
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* This file is part of OpenOffice.org.
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
|
|
* only, as published by the Free Software Foundation.
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License version 3 for more details
|
|
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
2008-04-11 06:19:10 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
|
|
* <http://www.openoffice.org/license.html>
|
|
|
|
* for a copy of the LGPLv3 License.
|
2007-07-05 07:31:52 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
#include "saldata.hxx"
|
|
|
|
#include "salinst.h"
|
|
|
|
#include "salmenu.h"
|
2008-01-14 15:19:15 +00:00
|
|
|
#include "salnsmenu.h"
|
2007-10-09 14:17:04 +00:00
|
|
|
#include "salframe.h"
|
2008-07-01 22:08:50 +00:00
|
|
|
#include "salbmp.h"
|
2007-10-09 14:17:04 +00:00
|
|
|
#include "vcl/svids.hrc"
|
|
|
|
#include "vcl/cmdevt.hxx"
|
2008-05-30 07:04:49 +00:00
|
|
|
#include "vcl/floatwin.hxx"
|
|
|
|
#include "vcl/window.h"
|
2007-10-09 14:17:04 +00:00
|
|
|
#include "vcl/window.hxx"
|
2008-03-05 16:02:21 +00:00
|
|
|
#include "vcl/svapp.hxx"
|
2008-07-01 22:08:50 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
#include "rtl/ustrbuf.hxx"
|
2008-07-25 08:09:09 +00:00
|
|
|
#include "aqua11ywrapper.h"
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = NULL;
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
@interface MainMenuSelector : NSObject
|
|
|
|
{
|
|
|
|
}
|
|
|
|
-(void)showDialog: (int)nDialog;
|
|
|
|
-(void)showPreferences: (id)sender;
|
|
|
|
-(void)showAbout: (id)sender;
|
|
|
|
@end
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
@implementation MainMenuSelector
|
|
|
|
-(void)showDialog: (int)nDialog
|
|
|
|
{
|
|
|
|
if( AquaSalMenu::pCurrentMenuBar )
|
|
|
|
{
|
|
|
|
const AquaSalFrame* pFrame = AquaSalMenu::pCurrentMenuBar->mpFrame;
|
|
|
|
if( pFrame && AquaSalFrame::isAlive( pFrame ) )
|
|
|
|
{
|
|
|
|
pFrame->CallCallback( SALEVENT_SHOWDIALOG, reinterpret_cast<void*>(nDialog) );
|
|
|
|
}
|
|
|
|
}
|
2008-03-05 16:02:21 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
String aDialog;
|
|
|
|
if( nDialog == SHOWDIALOG_ID_ABOUT )
|
|
|
|
aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "ABOUT" ) );
|
|
|
|
else if( nDialog == SHOWDIALOG_ID_PREFERENCES )
|
|
|
|
aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "PREFERENCES" ) );
|
|
|
|
const ApplicationEvent* pAppEvent = new ApplicationEvent( String(),
|
|
|
|
ApplicationAddress(),
|
|
|
|
ByteString( "SHOWDIALOG" ),
|
|
|
|
aDialog );
|
|
|
|
AquaSalInstance::aAppEventList.push_back( pAppEvent );
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
-(void)showPreferences: (id) sender
|
2007-07-05 07:31:52 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
[self showDialog: SHOWDIALOG_ID_PREFERENCES];
|
|
|
|
}
|
|
|
|
-(void)showAbout: (id) sender
|
|
|
|
{
|
|
|
|
[self showDialog: SHOWDIALOG_ID_ABOUT];
|
|
|
|
}
|
|
|
|
@end
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2008-08-18 12:29:30 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
// FIXME: currently this is leaked
|
|
|
|
static MainMenuSelector* pMainMenuSelector = nil;
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2008-03-05 16:02:21 +00:00
|
|
|
static void initAppMenu()
|
2007-10-09 14:17:04 +00:00
|
|
|
{
|
2007-07-05 07:31:52 +00:00
|
|
|
static bool bOnce = true;
|
|
|
|
if( bOnce )
|
|
|
|
{
|
|
|
|
bOnce = false;
|
|
|
|
|
|
|
|
ResMgr* pMgr = ImplGetResMgr();
|
|
|
|
if( pMgr )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
// get the main menu
|
|
|
|
NSMenu* pMainMenu = [NSApp mainMenu];
|
|
|
|
if( pMainMenu != nil )
|
2007-09-13 15:32:05 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
// create the action selector
|
|
|
|
pMainMenuSelector = [[MainMenuSelector alloc] init];
|
|
|
|
|
|
|
|
// get the proper submenu
|
|
|
|
NSMenu* pAppMenu = [[pMainMenu itemAtIndex: 0] submenu];
|
|
|
|
if( pAppMenu )
|
|
|
|
{
|
|
|
|
// insert about entry
|
|
|
|
String aAbout( ResId( SV_STDTEXT_ABOUT, *pMgr ) );
|
|
|
|
NSString* pString = CreateNSString( aAbout );
|
|
|
|
NSMenuItem* pNewItem = [pAppMenu insertItemWithTitle: pString
|
|
|
|
action: @selector(showAbout:)
|
|
|
|
keyEquivalent: @""
|
|
|
|
atIndex: 0];
|
|
|
|
if (pString)
|
|
|
|
[pString release];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
[pNewItem setTarget: pMainMenuSelector];
|
|
|
|
[pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// insert preferences entry
|
|
|
|
String aPref( ResId( SV_STDTEXT_PREFERENCES, *pMgr ) );
|
|
|
|
pString = CreateNSString( aPref );
|
|
|
|
pNewItem = [pAppMenu insertItemWithTitle: pString
|
|
|
|
action: @selector(showPreferences:)
|
|
|
|
keyEquivalent: @","
|
|
|
|
atIndex: 2];
|
|
|
|
if (pString)
|
|
|
|
[pString release];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
[pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask];
|
|
|
|
[pNewItem setTarget: pMainMenuSelector];
|
|
|
|
[pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
|
|
|
|
}
|
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
// WARNING: ultra ugly code ahead
|
2007-10-09 14:17:04 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
// rename standard entries
|
|
|
|
// rename "Services"
|
|
|
|
pNewItem = [pAppMenu itemAtIndex: 4];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
pString = CreateNSString( String( ResId( SV_MENU_MAC_SERVICES, *pMgr ) ) );
|
|
|
|
[pNewItem setTitle: pString];
|
|
|
|
if( pString )
|
|
|
|
[pString release];
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
// rename "Hide NewApplication"
|
|
|
|
pNewItem = [pAppMenu itemAtIndex: 6];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEAPP, *pMgr ) ) );
|
|
|
|
[pNewItem setTitle: pString];
|
|
|
|
if( pString )
|
|
|
|
[pString release];
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
// rename "Hide Others"
|
|
|
|
pNewItem = [pAppMenu itemAtIndex: 7];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEALL, *pMgr ) ) );
|
|
|
|
[pNewItem setTitle: pString];
|
|
|
|
if( pString )
|
|
|
|
[pString release];
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
// rename "Show all"
|
|
|
|
pNewItem = [pAppMenu itemAtIndex: 8];
|
|
|
|
if( pNewItem )
|
2007-10-09 14:17:04 +00:00
|
|
|
{
|
2008-04-17 07:04:04 +00:00
|
|
|
pString = CreateNSString( String( ResId( SV_MENU_MAC_SHOWALL, *pMgr ) ) );
|
|
|
|
[pNewItem setTitle: pString];
|
|
|
|
if( pString )
|
|
|
|
[pString release];
|
|
|
|
}
|
|
|
|
|
|
|
|
// rename "Quit NewApplication"
|
|
|
|
pNewItem = [pAppMenu itemAtIndex: 10];
|
|
|
|
if( pNewItem )
|
|
|
|
{
|
|
|
|
pString = CreateNSString( String( ResId( SV_MENU_MAC_QUITAPP, *pMgr ) ) );
|
|
|
|
[pNewItem setTitle: pString];
|
|
|
|
if( pString )
|
|
|
|
[pString release];
|
2007-10-09 14:17:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-13 15:32:05 +00:00
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-05 16:02:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
SalMenu* AquaSalInstance::CreateMenu( BOOL bMenuBar )
|
|
|
|
{
|
|
|
|
initAppMenu();
|
|
|
|
|
|
|
|
AquaSalMenu *pAquaSalMenu = new AquaSalMenu( bMenuBar );
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
return pAquaSalMenu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalInstance::DestroyMenu( SalMenu* pSalMenu )
|
|
|
|
{
|
|
|
|
delete pSalMenu;
|
|
|
|
}
|
|
|
|
|
|
|
|
SalMenuItem* AquaSalInstance::CreateMenuItem( const SalItemParams* pItemData )
|
|
|
|
{
|
|
|
|
if( !pItemData )
|
|
|
|
return NULL;
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenuItem *pSalMenuItem = new AquaSalMenuItem( pItemData );
|
2007-07-05 07:31:52 +00:00
|
|
|
|
|
|
|
return pSalMenuItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
|
|
|
|
{
|
|
|
|
delete pSalMenuItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AquaSalMenu
|
|
|
|
*/
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenu::AquaSalMenu( bool bMenuBar ) :
|
|
|
|
mbMenuBar( bMenuBar ),
|
|
|
|
mpMenu( nil ),
|
|
|
|
mpVCLMenu( NULL ),
|
|
|
|
mpFrame( NULL ),
|
|
|
|
mpParentSalMenu( NULL )
|
|
|
|
{
|
|
|
|
if( ! mbMenuBar )
|
|
|
|
{
|
|
|
|
mpMenu = [[SalNSMenu alloc] initWithMenu: this];
|
|
|
|
[mpMenu setDelegate: mpMenu];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mpMenu = [NSApp mainMenu];
|
|
|
|
}
|
|
|
|
[mpMenu setAutoenablesItems: NO];
|
|
|
|
}
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
AquaSalMenu::~AquaSalMenu()
|
|
|
|
{
|
2008-07-01 22:08:50 +00:00
|
|
|
// actually someone should have done AquaSalFrame::SetMenu( NULL )
|
|
|
|
// on our frame, alas it is not so
|
|
|
|
if( mpFrame && AquaSalFrame::isAlive( mpFrame ) && mpFrame->mpMenu == this )
|
|
|
|
const_cast<AquaSalFrame*>(mpFrame)->mpMenu = NULL;
|
|
|
|
|
2008-08-18 12:29:30 +00:00
|
|
|
// this should normally be empty already, but be careful...
|
|
|
|
for( size_t i = 0; i < maButtons.size(); i++ )
|
|
|
|
releaseButtonEntry( maButtons[i] );
|
|
|
|
maButtons.clear();
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
// is this leaking in some cases ? the release often leads to a duplicate release
|
|
|
|
// it seems the parent item gets ownership of the menu
|
2008-07-01 22:08:50 +00:00
|
|
|
if( mpMenu )
|
2007-10-09 14:17:04 +00:00
|
|
|
{
|
2008-07-01 22:08:50 +00:00
|
|
|
if( mbMenuBar )
|
|
|
|
{
|
|
|
|
if( pCurrentMenuBar == this )
|
|
|
|
{
|
|
|
|
// if the current menubar gets destroyed, set the default menubar
|
|
|
|
setDefaultMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// the system may still hold a reference on mpMenu
|
|
|
|
{
|
|
|
|
// so set the pointer to this AquaSalMenu to NULL
|
|
|
|
// to protect from calling a dead object
|
|
|
|
|
|
|
|
// in ! mbMenuBar case our mpMenu is actually a SalNSMenu*
|
|
|
|
// so we can safely cast here
|
|
|
|
[static_cast<SalNSMenu*>(mpMenu) setSalMenu: NULL];
|
|
|
|
/* #i89860# FIXME:
|
|
|
|
using [autorelease] here (and in AquaSalMenuItem::~AquaSalMenuItem)
|
|
|
|
instead of [release] fixes an occasional crash. That should
|
|
|
|
indicate that we release menus / menu items in the wrong order
|
|
|
|
somewhere, but I could not find that case.
|
|
|
|
*/
|
|
|
|
[mpMenu autorelease];
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-30 07:04:49 +00:00
|
|
|
sal_Int32 removeUnusedItemsRunner(NSMenu * pMenu)
|
|
|
|
{
|
|
|
|
NSArray * elements = [pMenu itemArray];
|
|
|
|
NSEnumerator * it = [elements objectEnumerator];
|
|
|
|
id elem;
|
|
|
|
NSMenuItem * lastDisplayedMenuItem = nil;
|
|
|
|
sal_Int32 drawnItems = 0;
|
|
|
|
bool firstEnabledItemIsNoSeparator = false;
|
|
|
|
while((elem=[it nextObject]) != nil) {
|
|
|
|
NSMenuItem * item = static_cast<NSMenuItem *>(elem);
|
|
|
|
if( (![item isEnabled] && ![item isSeparatorItem]) || ([item isSeparatorItem] && (lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem])) ) {
|
|
|
|
[[item menu]removeItem:item];
|
|
|
|
} else {
|
|
|
|
if( ! firstEnabledItemIsNoSeparator && [item isSeparatorItem] ) {
|
|
|
|
[[item menu]removeItem:item];
|
|
|
|
} else {
|
|
|
|
firstEnabledItemIsNoSeparator = true;
|
|
|
|
lastDisplayedMenuItem = item;
|
|
|
|
drawnItems++;
|
|
|
|
if( [item hasSubmenu] ) {
|
|
|
|
removeUnusedItemsRunner( [item submenu] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem]) {
|
|
|
|
[[lastDisplayedMenuItem menu]removeItem:lastDisplayedMenuItem];
|
|
|
|
}
|
|
|
|
return drawnItems;
|
|
|
|
}
|
|
|
|
|
2008-08-18 12:29:30 +00:00
|
|
|
bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags)
|
2008-05-30 07:04:49 +00:00
|
|
|
{
|
|
|
|
// do not use native popup menu when AQUA_NATIVE_MENUS is set to FALSE
|
|
|
|
if( ! VisibleMenuBar() ) {
|
2008-08-18 12:29:30 +00:00
|
|
|
return false;
|
2008-05-30 07:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set offsets for positioning
|
|
|
|
const float offset = 9.0;
|
|
|
|
const float lineHeight = 17.0;
|
|
|
|
|
|
|
|
// get the pointers
|
|
|
|
AquaSalFrame * pParentAquaSalFrame = (AquaSalFrame *) pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame();
|
|
|
|
NSWindow * pParentNSWindow = pParentAquaSalFrame->mpWindow;
|
|
|
|
NSView * pParentNSView = [pParentNSWindow contentView];
|
|
|
|
NSView * pPopupNSView = ((AquaSalFrame *) pWin->ImplGetWindow()->ImplGetFrame())->mpView;
|
|
|
|
NSRect popupFrame = [pPopupNSView frame];
|
|
|
|
|
|
|
|
// since we manipulate the menu below (removing entries)
|
|
|
|
// let's rather make a copy here and work with that
|
|
|
|
NSMenu* pCopyMenu = [mpMenu copy];
|
|
|
|
|
|
|
|
// filter disabled elements
|
|
|
|
sal_Int32 drawnItems = removeUnusedItemsRunner( pCopyMenu );
|
|
|
|
|
|
|
|
// create frame rect
|
|
|
|
NSRect displayPopupFrame = NSMakeRect( rRect.nLeft+(offset-1), rRect.nTop+(offset+1), popupFrame.size.width, 0 );
|
|
|
|
pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
|
|
|
|
|
|
|
|
// adjust frame rect when necessary
|
|
|
|
USHORT nArrangeIndex;
|
|
|
|
Point position = pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex );
|
2008-12-01 13:29:22 +00:00
|
|
|
if( position.Y() < rRect.nTop ) {
|
2008-05-30 07:04:49 +00:00
|
|
|
displayPopupFrame.origin.y += ( lineHeight*drawnItems );
|
|
|
|
}
|
2008-12-01 13:29:22 +00:00
|
|
|
if( position.X() < rRect.nLeft ) {
|
2008-05-30 07:04:49 +00:00
|
|
|
displayPopupFrame.origin.x -= popupFrame.size.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
// open popup menu
|
|
|
|
NSPopUpButtonCell * pPopUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
|
|
|
|
[pPopUpButtonCell setMenu: pCopyMenu];
|
|
|
|
[pPopUpButtonCell selectItem:nil];
|
2008-07-25 08:09:09 +00:00
|
|
|
[AquaA11yWrapper setPopupMenuOpen: YES];
|
2008-05-30 07:04:49 +00:00
|
|
|
[pPopUpButtonCell performClickWithFrame:displayPopupFrame inView:pParentNSView];
|
|
|
|
[pPopUpButtonCell release];
|
2008-07-25 08:09:09 +00:00
|
|
|
[AquaA11yWrapper setPopupMenuOpen: NO];
|
2008-05-30 07:04:49 +00:00
|
|
|
|
|
|
|
// clean up the copy
|
|
|
|
[pCopyMenu release];
|
2008-08-18 12:29:30 +00:00
|
|
|
return true;
|
2008-05-30 07:04:49 +00:00
|
|
|
}
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
int AquaSalMenu::getItemIndexByPos( USHORT nPos ) const
|
|
|
|
{
|
|
|
|
int nIndex = 0;
|
|
|
|
if( nPos == MENU_APPEND )
|
|
|
|
nIndex = [mpMenu numberOfItems];
|
|
|
|
else
|
|
|
|
nIndex = sal::static_int_cast<int>( mbMenuBar ? nPos+1 : nPos );
|
|
|
|
return nIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
const AquaSalFrame* AquaSalMenu::getFrame() const
|
|
|
|
{
|
|
|
|
const AquaSalMenu* pMenu = this;
|
|
|
|
while( pMenu && ! pMenu->mpFrame )
|
|
|
|
pMenu = pMenu->mpParentSalMenu;
|
|
|
|
return pMenu ? pMenu->mpFrame : NULL;
|
|
|
|
}
|
|
|
|
|
2008-03-05 16:02:21 +00:00
|
|
|
void AquaSalMenu::unsetMainMenu()
|
|
|
|
{
|
2008-07-01 22:08:50 +00:00
|
|
|
pCurrentMenuBar = NULL;
|
|
|
|
|
|
|
|
// remove items from main menu
|
|
|
|
NSMenu* pMenu = [NSApp mainMenu];
|
|
|
|
for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- )
|
|
|
|
[pMenu removeItemAtIndex: 1];
|
2008-03-05 16:02:21 +00:00
|
|
|
}
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
void AquaSalMenu::setMainMenu()
|
|
|
|
{
|
|
|
|
DBG_ASSERT( mbMenuBar, "setMainMenu on non menubar" );
|
|
|
|
if( mbMenuBar )
|
2007-07-05 07:31:52 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
if( pCurrentMenuBar != this )
|
|
|
|
{
|
2008-03-05 16:02:21 +00:00
|
|
|
unsetMainMenu();
|
2007-10-09 14:17:04 +00:00
|
|
|
// insert our items
|
|
|
|
for( unsigned int i = 0; i < maItems.size(); i++ )
|
|
|
|
{
|
|
|
|
NSMenuItem* pItem = maItems[i]->mpMenuItem;
|
|
|
|
[mpMenu insertItem: pItem atIndex: i+1];
|
|
|
|
}
|
|
|
|
pCurrentMenuBar = this;
|
2008-08-18 12:29:30 +00:00
|
|
|
|
|
|
|
// change status item
|
|
|
|
statusLayout();
|
2007-10-09 14:17:04 +00:00
|
|
|
}
|
|
|
|
enableMainMenu( true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-05 16:02:21 +00:00
|
|
|
void AquaSalMenu::setDefaultMenu()
|
|
|
|
{
|
|
|
|
NSMenu* pMenu = [NSApp mainMenu];
|
|
|
|
|
2008-07-01 22:08:50 +00:00
|
|
|
unsetMainMenu();
|
2008-03-05 16:02:21 +00:00
|
|
|
|
|
|
|
// insert default items
|
|
|
|
std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
|
2008-07-01 22:08:50 +00:00
|
|
|
for( unsigned int i = 0, nAddItems = rFallbackMenu.size(); i < nAddItems; i++ )
|
2008-03-05 16:02:21 +00:00
|
|
|
{
|
|
|
|
NSMenuItem* pItem = rFallbackMenu[i];
|
2008-07-01 22:08:50 +00:00
|
|
|
if( [pItem menu] == nil )
|
|
|
|
[pMenu insertItem: pItem atIndex: i+1];
|
2008-03-05 16:02:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
void AquaSalMenu::enableMainMenu( bool bEnable )
|
|
|
|
{
|
|
|
|
NSMenu* pMainMenu = [NSApp mainMenu];
|
|
|
|
if( pMainMenu )
|
|
|
|
{
|
|
|
|
// enable/disable items from main menu
|
|
|
|
int nItems = [pMainMenu numberOfItems];
|
|
|
|
for( int n = 1; n < nItems; n++ )
|
|
|
|
{
|
|
|
|
NSMenuItem* pItem = [pMainMenu itemAtIndex: n];
|
|
|
|
[pItem setEnabled: bEnable ? YES : NO];
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-05 16:02:21 +00:00
|
|
|
void AquaSalMenu::addFallbackMenuItem( NSMenuItem* pNewItem )
|
|
|
|
{
|
|
|
|
initAppMenu();
|
|
|
|
|
|
|
|
std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
|
|
|
|
|
|
|
|
// prevent duplicate insertion
|
|
|
|
int nItems = rFallbackMenu.size();
|
|
|
|
for( int i = 0; i < nItems; i++ )
|
|
|
|
{
|
|
|
|
if( rFallbackMenu[i] == pNewItem )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// push the item to the back and retain it
|
|
|
|
[pNewItem retain];
|
|
|
|
rFallbackMenu.push_back( pNewItem );
|
|
|
|
|
|
|
|
if( pCurrentMenuBar == NULL )
|
|
|
|
setDefaultMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::removeFallbackMenuItem( NSMenuItem* pOldItem )
|
|
|
|
{
|
|
|
|
std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
|
|
|
|
|
|
|
|
// find item
|
|
|
|
unsigned int nItems = rFallbackMenu.size();
|
|
|
|
for( unsigned int i = 0; i < nItems; i++ )
|
|
|
|
{
|
|
|
|
if( rFallbackMenu[i] == pOldItem )
|
|
|
|
{
|
|
|
|
// remove item and release
|
|
|
|
rFallbackMenu.erase( rFallbackMenu.begin() + i );
|
|
|
|
[pOldItem release];
|
|
|
|
|
|
|
|
if( pCurrentMenuBar == NULL )
|
|
|
|
setDefaultMenu();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
BOOL AquaSalMenu::VisibleMenuBar()
|
|
|
|
{
|
|
|
|
// Enable/disable experimental native menus code?
|
|
|
|
//
|
|
|
|
// To disable native menus, set the environment variable AQUA_NATIVE_MENUS to FALSE
|
|
|
|
|
|
|
|
static const char *pExperimental = getenv ("AQUA_NATIVE_MENUS");
|
|
|
|
|
2008-05-30 07:04:49 +00:00
|
|
|
if ( GetSalData()->mbIsTestTool || (pExperimental && !strcasecmp(pExperimental, "FALSE")) )
|
2007-07-05 07:31:52 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// End of experimental code enable/disable part
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::SetFrame( const SalFrame *pFrame )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
mpFrame = static_cast<const AquaSalFrame*>(pFrame);
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
|
2008-07-01 22:08:50 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
pAquaSalMenuItem->mpParentMenu = this;
|
|
|
|
DBG_ASSERT( pAquaSalMenuItem->mpVCLMenu == NULL ||
|
|
|
|
pAquaSalMenuItem->mpVCLMenu == mpVCLMenu ||
|
|
|
|
mpVCLMenu == NULL,
|
|
|
|
"resetting menu ?" );
|
|
|
|
if( pAquaSalMenuItem->mpVCLMenu )
|
|
|
|
mpVCLMenu = pAquaSalMenuItem->mpVCLMenu;
|
|
|
|
|
|
|
|
if( nPos == MENU_APPEND || nPos == maItems.size() )
|
|
|
|
maItems.push_back( pAquaSalMenuItem );
|
|
|
|
else if( nPos < maItems.size() )
|
|
|
|
maItems.insert( maItems.begin() + nPos, pAquaSalMenuItem );
|
2007-07-05 07:31:52 +00:00
|
|
|
else
|
2008-07-01 22:08:50 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
DBG_ERROR( "invalid item index in insert" );
|
2008-07-01 22:08:50 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
if( ! mbMenuBar || pCurrentMenuBar == this )
|
|
|
|
[mpMenu insertItem: pAquaSalMenuItem->mpMenuItem atIndex: getItemIndexByPos(nPos)];
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::RemoveItem( unsigned nPos )
|
|
|
|
{
|
2008-07-01 22:08:50 +00:00
|
|
|
AquaSalMenuItem* pRemoveItem = NULL;
|
|
|
|
if( nPos == MENU_APPEND || nPos == (maItems.size()-1) )
|
|
|
|
{
|
|
|
|
pRemoveItem = maItems.back();
|
2007-10-09 14:17:04 +00:00
|
|
|
maItems.pop_back();
|
2008-07-01 22:08:50 +00:00
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
else if( nPos < maItems.size() )
|
2008-07-01 22:08:50 +00:00
|
|
|
{
|
|
|
|
pRemoveItem = maItems[ nPos ];
|
2007-10-09 14:17:04 +00:00
|
|
|
maItems.erase( maItems.begin()+nPos );
|
2008-07-01 22:08:50 +00:00
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
else
|
2008-07-01 22:08:50 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
DBG_ERROR( "invalid item index in remove" );
|
2008-07-01 22:08:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pRemoveItem->mpParentMenu = NULL;
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
if( ! mbMenuBar || pCurrentMenuBar == this )
|
|
|
|
[mpMenu removeItemAtIndex: getItemIndexByPos(nPos)];
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
|
|
|
|
AquaSalMenu *subAquaSalMenu = static_cast<AquaSalMenu*>(pSubMenu);
|
2007-07-05 07:31:52 +00:00
|
|
|
|
|
|
|
if (subAquaSalMenu)
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
pAquaSalMenuItem->mpSubMenu = subAquaSalMenu;
|
|
|
|
if( subAquaSalMenu->mpParentSalMenu == NULL )
|
2007-09-13 15:32:05 +00:00
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
subAquaSalMenu->mpParentSalMenu = this;
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setSubmenu: subAquaSalMenu->mpMenu];
|
|
|
|
|
|
|
|
// set title of submenu
|
|
|
|
[subAquaSalMenu->mpMenu setTitle: [pAquaSalMenuItem->mpMenuItem title]];
|
|
|
|
}
|
|
|
|
else if( subAquaSalMenu->mpParentSalMenu != this )
|
|
|
|
{
|
|
|
|
// cocoa doesn't allow menus to be submenus of multiple
|
|
|
|
// menu items, so place a copy in the menu item instead ?
|
|
|
|
// let's hope that NSMenu copy does the right thing
|
|
|
|
NSMenu* pCopy = [subAquaSalMenu->mpMenu copy];
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setSubmenu: pCopy];
|
|
|
|
|
|
|
|
// set title of submenu
|
|
|
|
[pCopy setTitle: [pAquaSalMenuItem->mpMenuItem title]];
|
2007-09-13 15:32:05 +00:00
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
2008-07-01 22:08:50 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if( pAquaSalMenuItem->mpSubMenu )
|
|
|
|
{
|
|
|
|
if( pAquaSalMenuItem->mpSubMenu->mpParentSalMenu == this )
|
|
|
|
pAquaSalMenuItem->mpSubMenu->mpParentSalMenu = NULL;
|
|
|
|
}
|
|
|
|
pAquaSalMenuItem->mpSubMenu = NULL;
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setSubmenu: nil];
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::CheckItem( unsigned nPos, BOOL bCheck )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
if( nPos < maItems.size() )
|
|
|
|
{
|
|
|
|
NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
|
|
|
|
[pItem setState: bCheck ? NSOnState : NSOffState];
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::EnableItem( unsigned nPos, BOOL bEnable )
|
|
|
|
{
|
2007-10-09 14:17:04 +00:00
|
|
|
if( nPos < maItems.size() )
|
|
|
|
{
|
|
|
|
NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
|
|
|
|
[pItem setEnabled: bEnable ? YES : NO];
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-01 22:08:50 +00:00
|
|
|
void AquaSalMenu::SetItemImage( unsigned nPos, SalMenuItem* pSMI, const Image& rImage )
|
2007-07-05 07:31:52 +00:00
|
|
|
{
|
2008-07-01 22:08:50 +00:00
|
|
|
AquaSalMenuItem* pSalMenuItem = static_cast<AquaSalMenuItem*>( pSMI );
|
|
|
|
if( ! pSalMenuItem || ! pSalMenuItem->mpMenuItem )
|
|
|
|
return;
|
|
|
|
|
2008-08-18 12:29:30 +00:00
|
|
|
NSImage* pImage = CreateNSImage( rImage );
|
2008-07-01 22:08:50 +00:00
|
|
|
|
|
|
|
if( pImage )
|
|
|
|
{
|
|
|
|
[pSalMenuItem->mpMenuItem setImage: pImage];
|
|
|
|
[pImage release];
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )
|
|
|
|
{
|
|
|
|
if (!pSalMenuItem)
|
|
|
|
return;
|
|
|
|
|
|
|
|
AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) pSalMenuItem;
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
String aText( rText );
|
2007-07-05 07:31:52 +00:00
|
|
|
|
|
|
|
// Delete mnemonics
|
2007-10-09 14:17:04 +00:00
|
|
|
aText.EraseAllChars( '~' );
|
|
|
|
|
|
|
|
NSString* pString = CreateNSString( aText );
|
|
|
|
if (pString)
|
2008-07-01 22:08:50 +00:00
|
|
|
{
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setTitle: pString];
|
|
|
|
// if the menu item has a submenu, change its title as well
|
|
|
|
if (pAquaSalMenuItem->mpSubMenu)
|
|
|
|
[pAquaSalMenuItem->mpSubMenu->mpMenu setTitle: pString];
|
2007-10-09 14:17:04 +00:00
|
|
|
[pString release];
|
2008-07-01 22:08:50 +00:00
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName )
|
|
|
|
{
|
|
|
|
USHORT nModifier;
|
2007-10-09 14:17:04 +00:00
|
|
|
sal_Unicode nCommandKey = 0;
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
USHORT nKeyCode=rKeyCode.GetCode();
|
|
|
|
if( nKeyCode )
|
2007-07-05 07:31:52 +00:00
|
|
|
{
|
|
|
|
if ((nKeyCode>=KEY_A) && (nKeyCode<=KEY_Z)) // letter A..Z
|
2007-10-09 14:17:04 +00:00
|
|
|
nCommandKey = nKeyCode-KEY_A + 'a';
|
2007-07-05 07:31:52 +00:00
|
|
|
else if ((nKeyCode>=KEY_0) && (nKeyCode<=KEY_9)) // numbers 0..9
|
2007-10-09 14:17:04 +00:00
|
|
|
nCommandKey = nKeyCode-KEY_0 + '0';
|
|
|
|
else if ((nKeyCode>=KEY_F1) && (nKeyCode<=KEY_F26)) // function keys F1..F26
|
|
|
|
nCommandKey = nKeyCode-KEY_F1 + NSF1FunctionKey;
|
|
|
|
else if( nKeyCode == KEY_REPEAT )
|
|
|
|
nCommandKey = NSRedoFunctionKey;
|
|
|
|
else if( nKeyCode == KEY_SPACE )
|
|
|
|
nCommandKey = ' ';
|
2007-07-05 07:31:52 +00:00
|
|
|
else
|
2007-10-09 14:17:04 +00:00
|
|
|
{
|
2007-07-05 07:31:52 +00:00
|
|
|
switch (nKeyCode)
|
|
|
|
{
|
|
|
|
case KEY_ADD:
|
|
|
|
nCommandKey='+';
|
|
|
|
break;
|
|
|
|
case KEY_SUBTRACT:
|
|
|
|
nCommandKey='-';
|
|
|
|
break;
|
|
|
|
case KEY_MULTIPLY:
|
|
|
|
nCommandKey='*';
|
|
|
|
break;
|
|
|
|
case KEY_DIVIDE:
|
|
|
|
nCommandKey='/';
|
|
|
|
break;
|
|
|
|
case KEY_POINT:
|
|
|
|
nCommandKey='.';
|
|
|
|
break;
|
|
|
|
case KEY_LESS:
|
|
|
|
nCommandKey='<';
|
|
|
|
break;
|
|
|
|
case KEY_GREATER:
|
|
|
|
nCommandKey='>';
|
|
|
|
break;
|
|
|
|
case KEY_EQUAL:
|
|
|
|
nCommandKey='=';
|
|
|
|
break;
|
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
else // not even a code ? nonsense -> ignore
|
|
|
|
return;
|
|
|
|
|
|
|
|
DBG_ASSERT( nCommandKey, "unmapped accelerator key" );
|
2007-07-05 07:31:52 +00:00
|
|
|
|
|
|
|
nModifier=rKeyCode.GetAllModifier();
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
// should always use the command key
|
2008-04-17 07:04:04 +00:00
|
|
|
int nItemModifier = 0;
|
2007-07-05 07:31:52 +00:00
|
|
|
|
|
|
|
if (nModifier & KEY_SHIFT)
|
2007-10-09 14:17:04 +00:00
|
|
|
{
|
|
|
|
nItemModifier |= NSShiftKeyMask; // actually useful only for function keys
|
|
|
|
if( nKeyCode >= KEY_A && nKeyCode <= KEY_Z )
|
|
|
|
nCommandKey = nKeyCode - KEY_A + 'A';
|
|
|
|
}
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
if (nModifier & KEY_MOD1)
|
|
|
|
nItemModifier |= NSCommandKeyMask;
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
if(nModifier & KEY_MOD2)
|
2007-10-09 14:17:04 +00:00
|
|
|
nItemModifier |= NSAlternateKeyMask;
|
2007-07-05 07:31:52 +00:00
|
|
|
|
2008-04-17 07:04:04 +00:00
|
|
|
if(nModifier & KEY_MOD3)
|
|
|
|
nItemModifier |= NSControlKeyMask;
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) pSalMenuItem;
|
|
|
|
NSString* pString = CreateNSString( rtl::OUString( &nCommandKey, 1 ) );
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setKeyEquivalent: pString];
|
|
|
|
[pAquaSalMenuItem->mpMenuItem setKeyEquivalentModifierMask: nItemModifier];
|
|
|
|
if (pString)
|
|
|
|
[pString release];
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::GetSystemMenuData( SystemMenuData* pData )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-08-18 12:29:30 +00:00
|
|
|
AquaSalMenu::MenuBarButtonEntry* AquaSalMenu::findButtonItem( USHORT i_nItemId )
|
|
|
|
{
|
|
|
|
for( size_t i = 0; i < maButtons.size(); ++i )
|
|
|
|
{
|
|
|
|
if( maButtons[i].maButton.mnId == i_nItemId )
|
|
|
|
return &maButtons[i];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::statusLayout()
|
|
|
|
{
|
|
|
|
if( GetSalData()->mpStatusItem )
|
|
|
|
{
|
|
|
|
NSView* pView = [GetSalData()->mpStatusItem view];
|
|
|
|
if( [pView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is
|
|
|
|
[(OOStatusItemView*)pView layout];
|
|
|
|
else
|
|
|
|
DBG_ERROR( "someone stole our status view" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::releaseButtonEntry( MenuBarButtonEntry& i_rEntry )
|
|
|
|
{
|
|
|
|
if( i_rEntry.mpNSImage )
|
|
|
|
{
|
|
|
|
[i_rEntry.mpNSImage release];
|
|
|
|
i_rEntry.mpNSImage = nil;
|
|
|
|
}
|
|
|
|
if( i_rEntry.mpToolTipString )
|
|
|
|
{
|
|
|
|
[i_rEntry.mpToolTipString release];
|
|
|
|
i_rEntry.mpToolTipString = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AquaSalMenu::AddMenuBarButton( const SalMenuButtonItem& i_rNewItem )
|
|
|
|
{
|
|
|
|
if( ! mbMenuBar || ! VisibleMenuBar() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
MenuBarButtonEntry* pEntry = findButtonItem( i_rNewItem.mnId );
|
|
|
|
if( pEntry )
|
|
|
|
{
|
|
|
|
releaseButtonEntry( *pEntry );
|
|
|
|
pEntry->maButton = i_rNewItem;
|
|
|
|
pEntry->mpNSImage = CreateNSImage( i_rNewItem.maImage );
|
|
|
|
if( i_rNewItem.maToolTipText.getLength() )
|
|
|
|
pEntry->mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
maButtons.push_back( MenuBarButtonEntry( i_rNewItem ) );
|
|
|
|
maButtons.back().mpNSImage = CreateNSImage( i_rNewItem.maImage );
|
|
|
|
maButtons.back().mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
|
|
|
|
}
|
|
|
|
|
|
|
|
// lazy create status item
|
|
|
|
SalData::getStatusItem();
|
|
|
|
|
|
|
|
if( pCurrentMenuBar == this )
|
|
|
|
statusLayout();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AquaSalMenu::RemoveMenuBarButton( USHORT i_nId )
|
|
|
|
{
|
|
|
|
MenuBarButtonEntry* pEntry = findButtonItem( i_nId );
|
|
|
|
if( pEntry )
|
|
|
|
{
|
|
|
|
releaseButtonEntry( *pEntry );
|
|
|
|
// note: vector guarantees that its contents are in a plain array
|
|
|
|
maButtons.erase( maButtons.begin() + (pEntry - &maButtons[0]) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pCurrentMenuBar == this )
|
|
|
|
statusLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame )
|
|
|
|
{
|
|
|
|
if( GetSalData()->mnSystemVersion < VER_LEOPARD )
|
|
|
|
return Rectangle( Point( -1, -1 ), Size( 1, 1 ) );
|
|
|
|
|
|
|
|
if( ! i_pReferenceFrame || ! AquaSalFrame::isAlive( static_cast<AquaSalFrame*>(i_pReferenceFrame) ) )
|
|
|
|
return Rectangle();
|
|
|
|
|
|
|
|
MenuBarButtonEntry* pEntry = findButtonItem( i_nItemId );
|
|
|
|
|
|
|
|
if( ! pEntry )
|
|
|
|
return Rectangle();
|
|
|
|
|
|
|
|
NSStatusItem* pItem = SalData::getStatusItem();
|
|
|
|
if( ! pItem )
|
|
|
|
return Rectangle();
|
|
|
|
|
|
|
|
NSView* pView = [pItem view];
|
|
|
|
if( ! pView )
|
|
|
|
return Rectangle();
|
|
|
|
NSWindow* pWin = [pView window];
|
|
|
|
if( ! pWin )
|
|
|
|
return Rectangle();
|
|
|
|
|
|
|
|
NSRect aRect = [pWin frame];
|
|
|
|
aRect.origin = [pWin convertBaseToScreen: NSMakePoint( 0, 0 )];
|
|
|
|
|
|
|
|
// make coordinates relative to reference frame
|
|
|
|
static_cast<AquaSalFrame*>(i_pReferenceFrame)->CocoaToVCL( aRect.origin );
|
|
|
|
aRect.origin.x -= i_pReferenceFrame->maGeometry.nX;
|
|
|
|
aRect.origin.y -= i_pReferenceFrame->maGeometry.nY + aRect.size.height;
|
|
|
|
|
|
|
|
return Rectangle( Point( aRect.origin.x, aRect.origin.y ), Size( aRect.size.width, aRect.size.height ) );
|
|
|
|
}
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
// =======================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SalMenuItem
|
|
|
|
*/
|
|
|
|
|
2007-10-09 14:17:04 +00:00
|
|
|
AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) :
|
|
|
|
mnId( pItemData->nId ),
|
|
|
|
mpVCLMenu( pItemData->pMenu ),
|
|
|
|
mpParentMenu( NULL ),
|
|
|
|
mpSubMenu( NULL ),
|
|
|
|
mpMenuItem( nil )
|
|
|
|
{
|
|
|
|
String aText( pItemData->aText );
|
|
|
|
|
|
|
|
// Delete mnemonics
|
|
|
|
aText.EraseAllChars( '~' );
|
|
|
|
|
|
|
|
if (pItemData->eType == MENUITEM_SEPARATOR)
|
|
|
|
{
|
|
|
|
mpMenuItem = [NSMenuItem separatorItem];
|
|
|
|
// these can go occasionally go in and out of a menu, ensure their lifecycle
|
|
|
|
// also for the release in AquaSalMenuItem destructor
|
|
|
|
[mpMenuItem retain];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this];
|
|
|
|
[mpMenuItem setEnabled: YES];
|
|
|
|
NSString* pString = CreateNSString( aText );
|
|
|
|
if (pString)
|
2008-07-01 22:08:50 +00:00
|
|
|
{
|
|
|
|
[mpMenuItem setTitle: pString];
|
2007-10-09 14:17:04 +00:00
|
|
|
[pString release];
|
2008-07-01 22:08:50 +00:00
|
|
|
}
|
2007-10-09 14:17:04 +00:00
|
|
|
// anything but a separator should set a menu to dispatch to
|
|
|
|
DBG_ASSERT( mpVCLMenu, "no menu" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-05 07:31:52 +00:00
|
|
|
AquaSalMenuItem::~AquaSalMenuItem()
|
|
|
|
{
|
2008-06-13 07:43:48 +00:00
|
|
|
/* #i89860# FIXME:
|
|
|
|
using [autorelease] here (and in AquaSalMenu:::~AquaSalMenu) instead of
|
|
|
|
[release] fixes an occasional crash. That should indicate that we release
|
|
|
|
menus / menu items in the wrong order somewhere, but I
|
|
|
|
could not find that case.
|
|
|
|
*/
|
2007-10-09 14:17:04 +00:00
|
|
|
if( mpMenuItem )
|
2008-06-13 07:43:48 +00:00
|
|
|
[mpMenuItem autorelease];
|
2007-07-05 07:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------
|
2007-10-09 14:17:04 +00:00
|
|
|
|