1999-07-06 15:50:03 +00:00
|
|
|
/*
|
|
|
|
NSMenu.m
|
|
|
|
|
|
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
|
1999-07-18 03:53:42 +00:00
|
|
|
Author: Michael Hanni <mhanni@sprintmail.com>
|
|
|
|
Date: 1999
|
|
|
|
|
|
|
|
A completely rewritten version of the original source by Scott Christley.
|
1999-07-20 09:21:31 +00:00
|
|
|
and:
|
1999-07-18 03:53:42 +00:00
|
|
|
Author: Ovidiu Predescu <ovidiu@net-community.com>
|
|
|
|
Date: May 1997
|
1999-07-20 09:21:31 +00:00
|
|
|
and:
|
1999-07-18 03:53:42 +00:00
|
|
|
Author: Felipe A. Rodriguez <far@ix.netcom.com>
|
|
|
|
Date: July 1998
|
1999-07-06 15:50:03 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, write to the Free Software Foundation,
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
1997-09-23 22:43:24 +00:00
|
|
|
#include <gnustep/gui/config.h>
|
1997-02-18 00:29:25 +00:00
|
|
|
#include <Foundation/NSCoder.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
1999-03-11 12:34:04 +00:00
|
|
|
#include <Foundation/NSException.h>
|
1997-07-07 16:56:52 +00:00
|
|
|
#include <Foundation/NSProcessInfo.h>
|
1997-08-27 21:20:19 +00:00
|
|
|
#include <Foundation/NSString.h>
|
1998-12-16 15:21:55 +00:00
|
|
|
#include <Foundation/NSNotification.h>
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1997-02-18 00:29:25 +00:00
|
|
|
#include <AppKit/NSMatrix.h>
|
1997-07-07 16:56:52 +00:00
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
#include <AppKit/NSWindow.h>
|
|
|
|
#include <AppKit/NSEvent.h>
|
|
|
|
#include <AppKit/NSFont.h>
|
|
|
|
#include <AppKit/NSMenu.h>
|
1999-06-30 03:10:38 +00:00
|
|
|
#include <AppKit/NSMenuView.h>
|
|
|
|
#include <AppKit/NSMenuItemCell.h>
|
1999-07-30 22:10:02 +00:00
|
|
|
#include <AppKit/NSPopUpButton.h>
|
|
|
|
#include <AppKit/NSPopUpButtonCell.h>
|
1999-08-19 23:18:25 +00:00
|
|
|
#include <AppKit/NSScreen.h>
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
static NSZone *menuZone = NULL;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-08-19 23:18:25 +00:00
|
|
|
static NSString* NSMenuLocationsKey = @"NSMenuLocations";
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
@implementation NSMenu
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Class Methods
|
|
|
|
+ (void) initialize
|
1999-03-24 11:31:06 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
if (self == [NSMenu class])
|
|
|
|
{
|
|
|
|
[self setVersion: 1];
|
|
|
|
}
|
1999-03-24 11:31:06 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
+ (void) setMenuZone: (NSZone *)zone
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
menuZone = zone;
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Methods.
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) init
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
return [self initWithTitle: @"Menu"];
|
1999-10-20 17:29:56 +00:00
|
|
|
//return self;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-30 22:10:02 +00:00
|
|
|
- (id) initWithPopUpButton: (NSPopUpButton *)popb
|
|
|
|
{
|
|
|
|
NSRect aRect;
|
|
|
|
NSRect winRect = {{0, 0}, {20, 17}};
|
|
|
|
|
|
|
|
[super init];
|
|
|
|
|
|
|
|
// Create an array to store out cells.
|
|
|
|
menu_items = [NSMutableArray new];
|
|
|
|
|
|
|
|
// Create a NSMenuView to draw our cells.
|
|
|
|
aRect = [popb frame];
|
|
|
|
|
|
|
|
menu_view = [[NSMenuView alloc] initWithFrame: NSMakeRect(0,0,50,50)
|
|
|
|
cellSize: aRect.size];
|
|
|
|
|
|
|
|
// Set ourself as the menu for this view.
|
|
|
|
[menu_view setMenu: self];
|
|
|
|
|
|
|
|
// We have no supermenu.
|
|
|
|
menu_supermenu = nil;
|
|
|
|
menu_is_tornoff = NO;
|
|
|
|
menu_is_visible = NO;
|
|
|
|
menu_follow_transient = NO;
|
|
|
|
menu_is_beholdenToPopUpButton = YES;
|
|
|
|
ASSIGN(menu_popb, popb);
|
|
|
|
|
|
|
|
menu_changed = YES;
|
|
|
|
/* According to the spec, menus do autoenable by default */
|
|
|
|
menu_autoenable = YES;
|
|
|
|
|
|
|
|
aWindow = [[NSMenuWindow alloc] initWithContentRect:winRect
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreRetained
|
|
|
|
defer: NO];
|
|
|
|
[[aWindow contentView] addSubview:menu_view];
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) popupButton
|
|
|
|
{
|
|
|
|
return menu_popb;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) _isBeholdenToPopUpButton
|
|
|
|
{
|
|
|
|
return menu_is_beholdenToPopUpButton;
|
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) initWithTitle: (NSString *)aTitle
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-07-28 10:31:56 +00:00
|
|
|
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
|
|
|
|
NSApplication* theApp = [NSApplication sharedApplication];
|
|
|
|
NSRect winRect = {{0, 0}, {20, 17}};
|
1999-10-20 17:29:56 +00:00
|
|
|
//float titleWidth = 0;
|
1999-07-28 10:31:56 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
[super init];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Keep the title.
|
|
|
|
ASSIGN(menu_title, aTitle);
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Create an array to store out cells.
|
|
|
|
menu_items = [NSMutableArray new];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Create a NSMenuView to draw our cells.
|
1999-07-20 09:21:31 +00:00
|
|
|
menu_view = [[NSMenuView alloc] initWithFrame: NSMakeRect(0,0,50,50)];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Set ourself as the menu for this view.
|
1999-07-20 09:21:31 +00:00
|
|
|
[menu_view setMenu: self];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// We have no supermenu.
|
|
|
|
menu_supermenu = nil;
|
|
|
|
menu_is_tornoff = NO;
|
1999-07-28 10:31:56 +00:00
|
|
|
menu_is_visible = NO;
|
|
|
|
menu_follow_transient = NO;
|
1999-07-30 22:10:02 +00:00
|
|
|
menu_is_beholdenToPopUpButton = NO;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
menu_changed = YES;
|
1999-07-20 09:21:31 +00:00
|
|
|
/* According to the spec, menus do autoenable by default */
|
|
|
|
menu_autoenable = YES;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
aWindow = [[NSMenuWindow alloc] initWithContentRect:winRect
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreRetained
|
|
|
|
defer: NO];
|
|
|
|
bWindow = [[NSMenuWindow alloc] initWithContentRect:winRect
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreRetained
|
|
|
|
defer: NO];
|
|
|
|
|
|
|
|
titleView = [NSMenuWindowTitleView new];
|
1999-09-12 03:19:36 +00:00
|
|
|
[titleView setFrameOrigin: NSMakePoint(0, winRect.size.height-22)];
|
|
|
|
[titleView setFrameSize: NSMakeSize (winRect.size.width, 22)];
|
1999-07-28 10:31:56 +00:00
|
|
|
[[aWindow contentView] addSubview:menu_view];
|
|
|
|
[[aWindow contentView] addSubview:titleView];
|
|
|
|
[titleView setMenu: self];
|
|
|
|
|
|
|
|
[defaultCenter addObserver: self
|
|
|
|
selector: @selector(_showTornOffMenuIfAny:)
|
|
|
|
name: NSApplicationWillFinishLaunchingNotification
|
|
|
|
object: theApp];
|
1999-06-30 03:10:38 +00:00
|
|
|
return self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-13 01:39:46 +00:00
|
|
|
/*
|
1999-07-20 09:21:31 +00:00
|
|
|
* - (void)insertItem: (id <NSMenuItem>)newItem
|
|
|
|
* atIndex: (int)index
|
1999-07-13 01:39:46 +00:00
|
|
|
*
|
|
|
|
* This method has been modified to convert anything that conforms to the
|
|
|
|
* <NSMenuItem> Protocol into a NSMenuItemCell which will be added to the
|
|
|
|
* items array.
|
|
|
|
*
|
|
|
|
* Blame: Michael
|
|
|
|
*/
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) insertItem: (id <NSMenuItem>)newItem
|
|
|
|
atIndex: (int)index
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
1999-07-26 06:44:26 +00:00
|
|
|
NSNotificationCenter *nc;
|
|
|
|
NSDictionary *d;
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
if ([(id)newItem conformsToProtocol: @protocol(NSMenuItem)])
|
1999-07-13 01:39:46 +00:00
|
|
|
{
|
1999-07-30 22:10:02 +00:00
|
|
|
if ([(id)newItem isKindOfClass: [NSMenuItemCell class]]
|
|
|
|
|| [(id)newItem isKindOfClass: [NSPopUpButtonCell class]])
|
1999-07-26 06:44:26 +00:00
|
|
|
{
|
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
d = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:index]
|
|
|
|
forKey: @"NSMenuItemIndex"];
|
|
|
|
[nc postNotificationName: NSMenuDidAddItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
|
|
|
|
|
|
|
[menu_items insertObject: newItem atIndex: index];
|
|
|
|
}
|
1999-07-13 01:39:46 +00:00
|
|
|
else
|
|
|
|
{
|
1999-07-26 06:44:26 +00:00
|
|
|
|
|
|
|
// The item we received conformed to <NSMenuItem> which is good,
|
|
|
|
// but it wasn't an NSMenuItemCell which is bad. Therefore, we
|
|
|
|
// loop through the system and create an NSMenuItemCell for
|
|
|
|
// this bad boy.
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
[self insertItemWithTitle: [newItem title]
|
|
|
|
action: [newItem action]
|
|
|
|
keyEquivalent: [newItem keyEquivalent]
|
|
|
|
atIndex: index];
|
1999-07-13 01:39:46 +00:00
|
|
|
}
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
1999-07-13 01:39:46 +00:00
|
|
|
NSLog(@"You must use an object that conforms to NSMenuItem.\n");
|
|
|
|
|
|
|
|
menu_changed = YES;
|
1996-09-12 19:24:32 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id <NSMenuItem>) insertItemWithTitle: (NSString *)aString
|
1999-07-26 06:44:26 +00:00
|
|
|
action: (SEL)aSelector
|
|
|
|
keyEquivalent: (NSString *)charCode
|
|
|
|
atIndex: (unsigned int)index
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-07-30 22:10:02 +00:00
|
|
|
id anItem;
|
|
|
|
|
|
|
|
if (menu_is_beholdenToPopUpButton)
|
|
|
|
{
|
|
|
|
anItem = [NSPopUpButtonCell new];
|
|
|
|
[anItem setTarget: menu_popb];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
anItem = [NSMenuItemCell new];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
[anItem setTitle: aString];
|
|
|
|
[anItem setAction: aSelector];
|
|
|
|
[anItem setKeyEquivalent: charCode];
|
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
// Insert the new item into the stream.
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
[self insertItem:anItem atIndex:index];
|
|
|
|
|
|
|
|
// For returns sake.
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return anItem;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) addItem: (id <NSMenuItem>)newItem
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
[self insertItem: newItem atIndex: [menu_items count]];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id <NSMenuItem>) addItemWithTitle: (NSString *)aString
|
|
|
|
action: (SEL)aSelector
|
|
|
|
keyEquivalent: (NSString *)keyEquiv
|
1999-06-02 19:55:23 +00:00
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
return [self insertItemWithTitle: aString
|
|
|
|
action: aSelector
|
|
|
|
keyEquivalent: keyEquiv
|
|
|
|
atIndex: [menu_items count]];
|
1999-06-02 19:55:23 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) removeItem: (id <NSMenuItem>)anItem
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-07-26 06:44:26 +00:00
|
|
|
[self removeItemAtIndex:[menu_items indexOfObject: anItem]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeItemAtIndex: (int)index
|
|
|
|
{
|
|
|
|
NSNotificationCenter *nc;
|
|
|
|
NSDictionary *d;
|
|
|
|
id anItem = [menu_items objectAtIndex:index];
|
1996-10-03 18:45:41 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
if (!anItem)
|
|
|
|
return;
|
1996-09-12 19:24:32 +00:00
|
|
|
|
1999-07-30 22:10:02 +00:00
|
|
|
if ([(NSMenuItemCell *)anItem isKindOfClass: [NSMenuItemCell class]]
|
|
|
|
|| [(id)anItem isKindOfClass: [NSPopUpButtonCell class]])
|
1999-07-26 06:44:26 +00:00
|
|
|
{
|
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
d = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:index]
|
|
|
|
forKey: @"NSMenuItemIndex"];
|
|
|
|
[nc postNotificationName: NSMenuDidRemoveItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
|
|
|
|
|
|
|
[menu_items removeObjectAtIndex: index];
|
1999-07-20 09:21:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n");
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
|
|
|
menu_changed = YES;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
- (void) itemChanged: (id <NSMenuItem>)anObject
|
1999-03-11 12:34:04 +00:00
|
|
|
{
|
1999-07-26 06:44:26 +00:00
|
|
|
// another nebulous method in NSMenu. Is this correct?
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
NSNotificationCenter *nc;
|
|
|
|
NSDictionary *d;
|
1996-10-03 18:45:41 +00:00
|
|
|
|
1999-07-26 06:44:26 +00:00
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
d = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:[self indexOfItem: anObject]]
|
|
|
|
forKey: @"NSMenuItemIndex"];
|
|
|
|
[nc postNotificationName: NSMenuDidChangeItemNotification
|
|
|
|
object: self
|
|
|
|
userInfo: d];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-03-11 12:34:04 +00:00
|
|
|
- (id <NSMenuItem>) itemWithTag: (int)aTag
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
unsigned i, count = [menu_items count];
|
1997-07-07 16:56:52 +00:00
|
|
|
id menuCell;
|
|
|
|
|
1999-03-11 12:34:04 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
menuCell = [menu_items objectAtIndex: i];
|
1999-03-11 12:34:04 +00:00
|
|
|
if ([menuCell tag] == aTag)
|
1999-06-30 03:10:38 +00:00
|
|
|
return menuCell;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
return nil;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
- (id <NSMenuItem>) itemWithTitle: (NSString*)aString
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
unsigned i, count = [menu_items count];
|
|
|
|
id menuCell;
|
1997-10-09 22:55:31 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
for (i = 0; i < count; i++)
|
1999-03-11 12:34:04 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
menuCell = [menu_items objectAtIndex: i];
|
|
|
|
if ([[menuCell title] isEqual: aString])
|
|
|
|
return menuCell;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
return nil;
|
1999-03-11 12:34:04 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id <NSMenuItem>) itemAtIndex: (int)index
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-10-20 17:29:56 +00:00
|
|
|
if (index >= [menu_items count] || index < 0)
|
|
|
|
[NSException raise:NSRangeException format:@"menu index %i out of range",
|
|
|
|
index];
|
1999-07-20 09:21:31 +00:00
|
|
|
return [menu_items objectAtIndex: index];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) numberOfItems
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return [menu_items count];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSArray *) itemArray
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return (NSArray *)menu_items;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItem: (id <NSMenuItem>)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-07-30 22:10:02 +00:00
|
|
|
if (![(NSMenuItemCell *)anObject isKindOfClass: [NSMenuItemCell class]]
|
1999-08-19 23:18:25 +00:00
|
|
|
|| ![(id)anObject isKindOfClass: [NSPopUpButtonCell class]])
|
1999-07-20 09:21:31 +00:00
|
|
|
{
|
|
|
|
NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return [menu_items indexOfObject: anObject];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItemWithTitle: (NSString *)aTitle
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
id anItem;
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
if ((anItem = [self itemWithTitle: aTitle]))
|
|
|
|
return [menu_items indexOfObject: anItem];
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItemWithTag: (int)aTag
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
id anItem;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
if ((anItem = [self itemWithTag: aTag]))
|
|
|
|
return [menu_items indexOfObject: anItem];
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItemWithTarget: (id)anObject
|
|
|
|
andAction: (SEL)actionSelector
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItemWithRepresentedObject: (id)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-07-30 22:10:02 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0;i<[menu_items count];i++)
|
|
|
|
{
|
|
|
|
if ([[[menu_items objectAtIndex:i] representedObject]
|
|
|
|
isEqual:anObject])
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (int) indexOfItemWithSubmenu: (NSMenu *)anObject
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-08-19 23:18:25 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0;i<[menu_items count];i++)
|
|
|
|
{
|
|
|
|
if ([[[menu_items objectAtIndex:i] title]
|
|
|
|
isEqual:[anObject title]])
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
return -1;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// Dealing with submenus.
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setSubmenu: (NSMenu *)aMenu
|
|
|
|
forItem: (id <NSMenuItem>) anItem
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
[anItem setTarget: aMenu];
|
1999-03-11 12:34:04 +00:00
|
|
|
[anItem setAction: @selector(submenuAction:)];
|
1997-07-07 16:56:52 +00:00
|
|
|
if (aMenu)
|
1999-06-30 03:10:38 +00:00
|
|
|
aMenu->menu_supermenu = self;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
ASSIGN(aMenu->menu_title, [anItem title]);
|
|
|
|
|
|
|
|
// notification that the menu has changed.
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) submenuAction: (id)sender
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSMenu *) attachedMenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_attached_menu;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-03-11 12:34:04 +00:00
|
|
|
- (BOOL) isAttached
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
// eh?
|
|
|
|
return menu_supermenu && [menu_supermenu attachedMenu] == self;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) isTornOff
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_is_tornoff;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
- (NSPoint) locationForSubmenu: (NSMenu*)aSubmenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-07-28 10:31:56 +00:00
|
|
|
NSRect frame;
|
|
|
|
NSRect submenuFrame;
|
1999-09-07 08:59:35 +00:00
|
|
|
NSWindow *win_link;
|
1999-07-28 10:31:56 +00:00
|
|
|
|
|
|
|
if (![self isFollowTransient])
|
|
|
|
{
|
|
|
|
frame = [aWindow frame];
|
1999-09-07 08:59:35 +00:00
|
|
|
win_link = aWindow;
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
frame = [bWindow frame];
|
1999-09-07 08:59:35 +00:00
|
|
|
win_link = bWindow;
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aSubmenu)
|
|
|
|
{
|
|
|
|
submenuFrame = [aSubmenu->aWindow frame];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
submenuFrame = NSZeroRect;
|
|
|
|
|
1999-09-07 08:59:35 +00:00
|
|
|
if (NSInterfaceStyleForKey(@"NSMenuInterfaceStyle", nil) == GSWindowMakerInterfaceStyle)
|
|
|
|
{
|
|
|
|
NSRect aRect = [menu_view rectOfItemAtIndex:[self indexOfItemWithTitle:[aSubmenu title]]];
|
|
|
|
NSPoint subOrigin = [win_link convertBaseToScreen: NSMakePoint(aRect.origin.x, aRect.origin.y)];
|
|
|
|
|
|
|
|
return NSMakePoint (frame.origin.x + frame.size.width + 1,
|
1999-09-12 03:19:36 +00:00
|
|
|
subOrigin.y - (submenuFrame.size.height - 42));
|
1999-09-07 08:59:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NSMakePoint (frame.origin.x + frame.size.width + 1,
|
|
|
|
frame.origin.y + frame.size.height
|
|
|
|
- submenuFrame.size.height);
|
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSMenu *) supermenu
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_supermenu;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setSupermenu: (NSMenu *)supermenu
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
ASSIGN(menu_supermenu, supermenu);
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setAutoenablesItems: (BOOL)flag
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
menu_autoenable = flag;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) autoenablesItems
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_autoenable;
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) update
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
// FIXME: needs to be checked.
|
1999-07-20 09:21:31 +00:00
|
|
|
id cells;
|
|
|
|
unsigned i, count;
|
|
|
|
id theApp = [NSApplication sharedApplication];
|
1999-08-20 20:55:23 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
if (menu_changed)
|
|
|
|
[self sizeToFit];
|
1997-07-07 16:56:52 +00:00
|
|
|
|
1998-12-22 12:34:03 +00:00
|
|
|
if (![self autoenablesItems])
|
1997-07-07 16:56:52 +00:00
|
|
|
return;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
|
|
|
count = [menu_items count];
|
|
|
|
|
1997-07-07 16:56:52 +00:00
|
|
|
/* Temporary disable automatic displaying of menu */
|
1999-03-11 12:34:04 +00:00
|
|
|
[self setMenuChangedMessagesEnabled: NO];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1998-12-01 10:24:19 +00:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
id<NSMenuItem> cell = [menu_items objectAtIndex: i];
|
|
|
|
SEL action = [cell action];
|
|
|
|
id target;
|
|
|
|
NSWindow *keyWindow;
|
|
|
|
NSWindow *mainWindow;
|
|
|
|
id responder;
|
|
|
|
id delegate;
|
|
|
|
id validator = nil;
|
|
|
|
BOOL wasEnabled = [cell isEnabled];
|
|
|
|
BOOL shouldBeEnabled;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1998-12-01 10:24:19 +00:00
|
|
|
/* Update the submenu items if any */
|
|
|
|
if ([cell hasSubmenu])
|
1999-06-30 03:10:38 +00:00
|
|
|
[[cell target] update];
|
|
|
|
|
1998-12-01 10:24:19 +00:00
|
|
|
/* If there is no action - there can be no validator for the cell */
|
|
|
|
if (action)
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
/* If there is a target use that for validation (or nil). */
|
|
|
|
if ((target = [cell target]))
|
|
|
|
{
|
|
|
|
if ([target respondsToSelector: action])
|
|
|
|
{
|
|
|
|
validator = target;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
validator = [theApp targetForAction: action];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-12-01 10:24:19 +00:00
|
|
|
if (validator == nil)
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
shouldBeEnabled = NO;
|
|
|
|
}
|
1999-07-20 09:21:31 +00:00
|
|
|
else if ([validator respondsToSelector: @selector(validateMenuItem:)])
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
shouldBeEnabled = [validator validateMenuItem: cell];
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
else
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
shouldBeEnabled = YES;
|
|
|
|
}
|
|
|
|
|
1998-12-01 10:24:19 +00:00
|
|
|
if (shouldBeEnabled != wasEnabled)
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
[cell setEnabled: shouldBeEnabled];
|
1999-08-20 20:55:23 +00:00
|
|
|
[[self window] display];
|
1999-08-19 23:18:25 +00:00
|
|
|
// [menu_view setNeedsDisplay:YES];
|
|
|
|
// [menu_view setNeedsDisplayInRect:[menu_view rectOfItemAtIndex:i]];
|
1999-06-30 03:10:38 +00:00
|
|
|
// FIXME
|
|
|
|
// [menuCells setNeedsDisplayInRect: [menuCells cellFrameAtRow: i]];
|
|
|
|
}
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1998-12-22 12:34:03 +00:00
|
|
|
/* Reenable displaying of menus */
|
1999-03-11 12:34:04 +00:00
|
|
|
[self setMenuChangedMessagesEnabled: YES];
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
- (BOOL) performKeyEquivalent: (NSEvent*)theEvent
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
unsigned count = [menu_items count];
|
|
|
|
NSEventType type = [theEvent type];
|
|
|
|
|
|
|
|
if (type != NSKeyDown && type != NSKeyUp)
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
id<NSMenuItem> cell = [menu_items objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([cell hasSubmenu])
|
|
|
|
{
|
|
|
|
if ([[cell target] performKeyEquivalent: theEvent])
|
|
|
|
{
|
|
|
|
/* The event has been handled by a cell in submenu */
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-07-20 09:21:31 +00:00
|
|
|
if ([[cell keyEquivalent] isEqual:
|
1999-06-30 03:10:38 +00:00
|
|
|
[theEvent charactersIgnoringModifiers]])
|
|
|
|
{
|
|
|
|
[menu_view lockFocus];
|
|
|
|
[(id)cell performClick: self];
|
|
|
|
[menu_view unlockFocus];
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
1999-03-11 12:34:04 +00:00
|
|
|
- (void) performActionForItem: (id <NSMenuItem>)cell
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
1998-12-16 15:21:55 +00:00
|
|
|
NSNotificationCenter *nc;
|
|
|
|
NSDictionary *d;
|
1997-07-07 16:56:52 +00:00
|
|
|
|
|
|
|
if (![cell isEnabled])
|
|
|
|
return;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1998-12-16 15:21:55 +00:00
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
d = [NSDictionary dictionaryWithObject: cell forKey: @"MenuItem"];
|
|
|
|
[nc postNotificationName: NSMenuWillSendActionNotification
|
1998-12-22 12:34:03 +00:00
|
|
|
object: self
|
|
|
|
userInfo: d];
|
1998-12-16 15:21:55 +00:00
|
|
|
[[NSApplication sharedApplication] sendAction: [cell action]
|
1998-12-22 12:34:03 +00:00
|
|
|
to: [cell target]
|
|
|
|
from: cell];
|
1998-12-16 15:21:55 +00:00
|
|
|
[nc postNotificationName: NSMenuDidSendActionNotification
|
1999-06-30 03:10:38 +00:00
|
|
|
object: self
|
|
|
|
userInfo: d];
|
1996-09-12 19:24:32 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setTitle: (NSString*)aTitle
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
ASSIGN(menu_title, aTitle);
|
|
|
|
[self sizeToFit];
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (NSString*) title
|
1996-05-30 20:03:15 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_title;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-05-30 20:03:15 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setMenuRepresentation: (id)menuRep
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
ASSIGN(menu_rep, menuRep);
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-12-05 13:07:59 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) menuRepresentation
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_rep;
|
1996-05-30 20:03:15 +00:00
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) setMenuChangedMessagesEnabled: (BOOL)flag
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
menu_ChangedMessagesEnabled = flag;
|
|
|
|
}
|
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (BOOL) menuChangedMessagesEnabled
|
1997-12-04 01:58:57 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return menu_ChangedMessagesEnabled;
|
1997-12-04 01:58:57 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
- (void) sizeToFit
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
|
|
|
NSRect mFrame;
|
|
|
|
NSSize size;
|
|
|
|
|
1999-10-20 17:29:56 +00:00
|
|
|
|
|
|
|
//-setTitleWidth: ends up calling -sizeToFit.
|
|
|
|
[menu_view setTitleWidth:[[NSFont systemFontOfSize:12] widthOfString:menu_title]];
|
1999-07-28 10:31:56 +00:00
|
|
|
mFrame = [menu_view frame];
|
1999-07-30 22:10:02 +00:00
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
size.width = mFrame.size.width;
|
1999-07-30 22:10:02 +00:00
|
|
|
size.height = mFrame.size.height;
|
|
|
|
|
|
|
|
if (!menu_is_beholdenToPopUpButton)
|
|
|
|
{
|
1999-09-12 03:19:36 +00:00
|
|
|
size.height += 22;
|
1999-08-19 23:18:25 +00:00
|
|
|
[aWindow setContentSize: size];
|
|
|
|
[bWindow setContentSize: size];
|
1999-08-20 20:55:23 +00:00
|
|
|
[menu_view setFrameOrigin: NSMakePoint(0, 0)];
|
1999-09-12 03:19:36 +00:00
|
|
|
[titleView setFrame: NSMakeRect(0,size.height-22,size.width,22)];
|
1999-07-30 22:10:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[aWindow setContentSize: size];
|
|
|
|
}
|
|
|
|
|
1999-08-20 20:55:23 +00:00
|
|
|
[aWindow display];
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
menu_changed = NO;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) helpRequested: (NSEvent *)event
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
// Won't be implemented until we have NSHelp*
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
// NSCoding
|
1999-07-20 09:21:31 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
|
1999-07-20 09:21:31 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1996-09-12 19:24:32 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
//NSCopying
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1997-07-07 16:56:52 +00:00
|
|
|
{
|
1999-06-30 03:10:38 +00:00
|
|
|
return self;
|
1997-07-07 16:56:52 +00:00
|
|
|
}
|
1996-09-12 19:24:32 +00:00
|
|
|
@end
|
1999-07-28 10:31:56 +00:00
|
|
|
|
|
|
|
@implementation NSMenu (GNUstepPrivate)
|
|
|
|
|
1999-08-19 23:18:25 +00:00
|
|
|
- (void)_showTornOffMenuIfAny: (NSNotification*)notification
|
|
|
|
{
|
|
|
|
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSDictionary* menuLocations = [defaults objectForKey: NSMenuLocationsKey];
|
|
|
|
NSString* key;
|
|
|
|
NSArray* array;
|
|
|
|
|
|
|
|
if ([[NSApplication sharedApplication] mainMenu] == self)
|
|
|
|
key = nil; // Ignore the main menu
|
|
|
|
else
|
|
|
|
key = [self title];
|
|
|
|
|
|
|
|
if (key)
|
|
|
|
{
|
|
|
|
array = [menuLocations objectForKey: key];
|
|
|
|
if (array && [array isKindOfClass: [NSArray class]])
|
|
|
|
{
|
|
|
|
[titleView windowBecomeTornOff];
|
|
|
|
[self _setTornOff:YES];
|
|
|
|
[self display];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
- (BOOL) isFollowTransient
|
|
|
|
{
|
|
|
|
return menu_follow_transient;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _setTornOff:(BOOL)flag
|
|
|
|
{
|
|
|
|
menu_is_tornoff = flag;
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
[[[self supermenu] menuView] setHighlightedItemIndex:-1];
|
1999-08-19 23:18:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
if (flag)
|
|
|
|
{
|
|
|
|
if (menu_supermenu)
|
|
|
|
{
|
|
|
|
menu_supermenu->menu_attached_menu = nil;
|
|
|
|
menu_supermenu = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _performMenuClose:(id)sender
|
|
|
|
{
|
1999-08-19 23:18:25 +00:00
|
|
|
NSUserDefaults* defaults;
|
|
|
|
NSMutableDictionary* menuLocations;
|
|
|
|
NSString* key;
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
[self _setTornOff:NO];
|
|
|
|
[self close];
|
|
|
|
[titleView _releaseCloseButton];
|
1999-08-19 23:18:25 +00:00
|
|
|
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
menuLocations = [[[defaults objectForKey: NSMenuLocationsKey]
|
|
|
|
mutableCopy] autorelease];
|
|
|
|
|
|
|
|
key = [self title]; // Remove window's position$
|
|
|
|
if (key) // info from defaults db
|
|
|
|
{
|
|
|
|
[menuLocations removeObjectForKey: key];
|
|
|
|
[defaults setObject: menuLocations forKey: NSMenuLocationsKey];
|
|
|
|
[defaults synchronize];
|
|
|
|
}
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
1999-09-07 08:59:35 +00:00
|
|
|
- (void) _rightMouseDisplay
|
|
|
|
{
|
|
|
|
// TODO: implement this method
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
- (void) display
|
|
|
|
{
|
|
|
|
if (menu_changed)
|
|
|
|
[self sizeToFit];
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
if (menu_supermenu && ![self isTornOff]) // query super menu for
|
1999-08-19 23:18:25 +00:00
|
|
|
{ // position
|
1999-09-12 03:19:36 +00:00
|
|
|
[aWindow setFrameOrigin:[menu_supermenu locationForSubmenu: self]];
|
1999-07-28 10:31:56 +00:00
|
|
|
menu_supermenu->menu_attached_menu = self;
|
1999-08-19 23:18:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSDictionary* menuLocations = [defaults
|
|
|
|
objectForKey: NSMenuLocationsKey];
|
|
|
|
NSString* key;
|
|
|
|
NSArray* array;
|
|
|
|
NSPoint origin;
|
|
|
|
|
|
|
|
if ([[NSApplication sharedApplication] mainMenu] == self)
|
|
|
|
key = @"Main menu";
|
|
|
|
else
|
|
|
|
key = [self title];
|
|
|
|
|
|
|
|
if (key)
|
|
|
|
{
|
|
|
|
array = [menuLocations objectForKey: key];
|
|
|
|
if (array && [array isKindOfClass: [NSArray class]])
|
|
|
|
{
|
|
|
|
origin.x = [[array objectAtIndex: 0] floatValue];
|
|
|
|
origin.y = [[array objectAtIndex: 1] floatValue];
|
|
|
|
[aWindow setFrameOrigin: origin];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float aPoint = [[NSScreen mainScreen] frame].size.height - [aWindow frame].size.height;
|
|
|
|
|
|
|
|
[aWindow setFrameOrigin:NSMakePoint(0,aPoint)];
|
|
|
|
[bWindow setFrameOrigin:NSMakePoint(0,aPoint)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[self submenuAction: nil];
|
1999-07-28 10:31:56 +00:00
|
|
|
|
|
|
|
menu_is_visible = YES;
|
1999-07-30 22:10:02 +00:00
|
|
|
[aWindow orderFront:nil];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) displayTransient
|
|
|
|
{
|
|
|
|
menu_follow_transient = YES;
|
|
|
|
|
|
|
|
if (menu_supermenu) // query super menu for our
|
|
|
|
{ // position
|
|
|
|
NSPoint location = [menu_supermenu locationForSubmenu: self];
|
|
|
|
|
|
|
|
[bWindow setFrameOrigin: location];
|
|
|
|
menu_supermenu->menu_attached_menu = self;
|
|
|
|
}
|
|
|
|
|
|
|
|
[menu_view removeFromSuperviewWithoutNeedingDisplay];
|
|
|
|
[titleView removeFromSuperviewWithoutNeedingDisplay];
|
|
|
|
|
|
|
|
[titleView _releaseCloseButton];
|
|
|
|
|
|
|
|
[[bWindow contentView] addSubview:menu_view];
|
|
|
|
[[bWindow contentView] addSubview:titleView];
|
|
|
|
|
|
|
|
[bWindow orderFront:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) close
|
|
|
|
{
|
|
|
|
[aWindow orderOut:self];
|
|
|
|
menu_is_visible = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) closeTransient
|
|
|
|
{
|
|
|
|
[bWindow orderOut:self];
|
|
|
|
[menu_view removeFromSuperviewWithoutNeedingDisplay];
|
|
|
|
[titleView removeFromSuperviewWithoutNeedingDisplay];
|
|
|
|
|
|
|
|
[[aWindow contentView] addSubview:menu_view];
|
|
|
|
[titleView _addCloseButton];
|
|
|
|
[[aWindow contentView] addSubview:titleView];
|
|
|
|
[[aWindow contentView] setNeedsDisplay:YES];
|
|
|
|
|
|
|
|
menu_follow_transient = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSWindow *) window
|
|
|
|
{
|
|
|
|
return (NSWindow *)aWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSMenuView *) menuView
|
|
|
|
{
|
|
|
|
return menu_view;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMenuWindow
|
1999-10-23 02:48:20 +00:00
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
1999-10-23 02:48:20 +00:00
|
|
|
if (self == [NSMenuWindow class])
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
|
|
|
[self setVersion: 1];
|
|
|
|
}
|
|
|
|
}
|
1999-10-23 02:48:20 +00:00
|
|
|
|
1999-11-15 21:45:56 +00:00
|
|
|
- (id) init
|
1999-10-23 02:48:20 +00:00
|
|
|
{
|
1999-11-15 21:45:56 +00:00
|
|
|
return [self initWithContentRect: NSZeroRect
|
|
|
|
styleMask: NSBorderlessWindowMask
|
|
|
|
backing: NSBackingStoreBuffered
|
|
|
|
defer: NO];
|
1999-10-23 02:48:20 +00:00
|
|
|
}
|
|
|
|
|
1999-11-15 21:45:56 +00:00
|
|
|
- (BOOL) canBecomeMainWindow
|
1999-10-23 02:48:20 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
1999-11-15 21:45:56 +00:00
|
|
|
- (BOOL) canBecomeKeyWindow
|
1999-10-23 02:48:20 +00:00
|
|
|
{
|
1999-11-15 21:45:56 +00:00
|
|
|
return NO;
|
1999-10-23 02:48:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) worksWhenModal
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMenuWindowTitleView
|
|
|
|
- (BOOL) acceptsFirstMouse: (NSEvent *)theEvent
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setMenu: (NSMenu*)aMenu { menu = aMenu; }
|
|
|
|
- (NSMenu*)menu { return menu; }
|
|
|
|
|
1999-08-31 09:19:39 +00:00
|
|
|
- (void) drawRect: (NSRect)rect
|
1999-07-28 10:31:56 +00:00
|
|
|
{
|
|
|
|
NSRect floodRect = rect;
|
|
|
|
|
|
|
|
NSDrawButton(rect, rect);
|
|
|
|
|
|
|
|
floodRect.origin.x += 1;
|
|
|
|
floodRect.origin.y += 2;
|
|
|
|
floodRect.size.height -= 3;
|
|
|
|
floodRect.size.width -= 3;
|
1999-08-31 09:19:39 +00:00
|
|
|
[[NSColor windowFrameColor] set];
|
1999-07-28 10:31:56 +00:00
|
|
|
NSRectFill(floodRect);
|
|
|
|
|
1999-08-31 09:19:39 +00:00
|
|
|
[[NSColor windowFrameTextColor] set];
|
1999-07-28 10:31:56 +00:00
|
|
|
[[NSFont boldSystemFontOfSize:12] set];
|
|
|
|
PSmoveto(rect.origin.x + 5, rect.origin.y + 6);
|
|
|
|
PSshow([[menu title] cString]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) mouseDown: (NSEvent*)theEvent
|
|
|
|
{
|
1999-08-19 23:18:25 +00:00
|
|
|
NSUserDefaults *defaults;
|
|
|
|
NSMutableDictionary *menuLocations;
|
|
|
|
NSMenu *appMainMenu;
|
|
|
|
NSPoint origin;
|
|
|
|
NSArray* array;
|
|
|
|
NSString* key;
|
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
NSPoint lastLocation;
|
|
|
|
NSPoint location;
|
|
|
|
unsigned eventMask = NSLeftMouseUpMask | NSLeftMouseDownMask
|
|
|
|
| NSPeriodicMask | NSRightMouseUpMask;
|
|
|
|
BOOL done = NO;
|
|
|
|
NSApplication *theApp = [NSApplication sharedApplication];
|
|
|
|
NSDate *theDistantFuture = [NSDate distantFuture];
|
|
|
|
|
|
|
|
lastLocation = [theEvent locationInWindow];
|
|
|
|
|
|
|
|
if ([menu supermenu])
|
|
|
|
{
|
|
|
|
[self windowBecomeTornOff];
|
|
|
|
[menu _setTornOff:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
[NSEvent startPeriodicEventsAfterDelay: 0.02 withPeriod: 0.02];
|
|
|
|
|
|
|
|
while (!done)
|
|
|
|
{
|
|
|
|
theEvent = [theApp nextEventMatchingMask: eventMask
|
|
|
|
untilDate: theDistantFuture
|
|
|
|
inMode: NSEventTrackingRunLoopMode
|
|
|
|
dequeue: YES];
|
|
|
|
|
|
|
|
switch ([theEvent type])
|
|
|
|
{
|
|
|
|
case NSRightMouseUp:
|
|
|
|
case NSLeftMouseUp:
|
|
|
|
/* right mouse up or left mouse up means we're done */
|
|
|
|
done = YES;
|
|
|
|
break;
|
|
|
|
case NSPeriodic:
|
|
|
|
location = [window mouseLocationOutsideOfEventStream];
|
|
|
|
if (NSEqualPoints(location, lastLocation) == NO)
|
|
|
|
{
|
|
|
|
NSMenu *aMenu = menu;
|
|
|
|
BOOL aDone = NO;
|
|
|
|
NSPoint origin = [window frame].origin;
|
|
|
|
|
|
|
|
origin.x += (location.x - lastLocation.x);
|
|
|
|
origin.y += (location.y - lastLocation.y);
|
|
|
|
[window setFrameOrigin: origin];
|
|
|
|
|
1999-08-03 21:55:08 +00:00
|
|
|
/* FIXME: Michael wrote this crappy hack.
|
1999-07-28 10:31:56 +00:00
|
|
|
while (!aDone)
|
|
|
|
{
|
|
|
|
if ((aMenu = [aMenu attachedMenu]))
|
|
|
|
{
|
|
|
|
NSPoint origin;
|
|
|
|
|
|
|
|
if ([aMenu isTornOff])
|
|
|
|
{
|
|
|
|
aDone = YES;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
origin = [[aMenu window] frame].origin;
|
|
|
|
|
|
|
|
origin.x += (location.x - lastLocation.x);
|
|
|
|
origin.y += (location.y - lastLocation.y);
|
|
|
|
[[aMenu window] setFrameOrigin: origin];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
aDone = YES;
|
|
|
|
}
|
1999-08-03 21:55:08 +00:00
|
|
|
*/
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[NSEvent stopPeriodicEvents];
|
1999-08-19 23:18:25 +00:00
|
|
|
|
1999-07-28 10:31:56 +00:00
|
|
|
// save position code goes here. FIXME.
|
1999-08-19 23:18:25 +00:00
|
|
|
appMainMenu = [NSApp mainMenu];
|
|
|
|
defaults = [NSUserDefaults standardUserDefaults];
|
|
|
|
menuLocations = [[[defaults objectForKey: NSMenuLocationsKey] mutableCopy] autorelease];
|
|
|
|
|
|
|
|
if (!menuLocations)
|
|
|
|
menuLocations = [NSMutableDictionary dictionaryWithCapacity: 2];
|
|
|
|
origin = [[menu window] frame].origin;
|
|
|
|
array = [NSArray arrayWithObjects:
|
|
|
|
[[NSNumber numberWithInt: origin.x] stringValue],
|
|
|
|
[[NSNumber numberWithInt: origin.y] stringValue], nil];
|
|
|
|
|
|
|
|
if (menu == appMainMenu)
|
|
|
|
key = @"Main menu";
|
|
|
|
else
|
|
|
|
key = [menu title]; // Save menu window pos
|
|
|
|
|
|
|
|
[menuLocations setObject: array forKey: key]; // in defaults databa
|
|
|
|
[defaults setObject: menuLocations forKey: NSMenuLocationsKey];
|
|
|
|
[defaults synchronize];
|
1999-07-28 10:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) windowBecomeTornOff
|
|
|
|
{
|
|
|
|
if ([menu isTornOff]) // do nothing if menu
|
|
|
|
return; // is already torn off
|
|
|
|
else
|
|
|
|
{ // show close button
|
|
|
|
NSImage* closeImage = [NSImage imageNamed: @"common_Close"];
|
|
|
|
NSImage* closeHImage = [NSImage imageNamed: @"common_CloseH"];
|
|
|
|
NSSize imageSize = [closeImage size];
|
|
|
|
NSRect rect = { { frame.size.width - imageSize.width - 4,
|
|
|
|
(frame.size.height - imageSize.height) / 2},
|
|
|
|
{ imageSize.height, imageSize.width } };
|
|
|
|
int mask = NSViewMinXMargin | NSViewMinYMargin | NSViewMaxYMargin;
|
|
|
|
|
|
|
|
button = [[NSButton alloc] initWithFrame: rect];
|
|
|
|
[button setButtonType: NSMomentaryLight]; // configure the menu's
|
|
|
|
[button setImagePosition: NSImageOnly]; // close button
|
|
|
|
[button setImage: closeImage];
|
|
|
|
[button setAlternateImage: closeHImage];
|
|
|
|
[button setBordered: NO];
|
|
|
|
[button setTarget: menu];
|
|
|
|
[button setAction: @selector(_performMenuClose:)];
|
|
|
|
[button setAutoresizingMask: NSViewMinXMargin];
|
|
|
|
|
|
|
|
[self addSubview: button];
|
|
|
|
[self setAutoresizingMask: mask];
|
|
|
|
|
|
|
|
[button display];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _releaseCloseButton
|
|
|
|
{
|
|
|
|
[button retain];
|
|
|
|
[button removeFromSuperview];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _addCloseButton
|
|
|
|
{
|
|
|
|
[self addSubview:button];
|
|
|
|
}
|
|
|
|
@end /* NSMenuWindowTitleView */
|
|
|
|
|